summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYaroslav Brustinov <ybrustin@cisco.com>2016-11-07 10:36:10 +0200
committerYaroslav Brustinov <ybrustin@cisco.com>2016-11-07 10:36:10 +0200
commit93dc74335a8082e0f54b1da7f6fc6e43ff3c10ee (patch)
tree3befab98de04fdbb63807c6db1844028ae50d8b6
parentbdd1dea5e21a00b6af1b0ded09e7d528485d5196 (diff)
parent5925379b5fb30e548f1ba4e804af9865de8903ae (diff)
Add 'doc/' from commit '5925379b5fb30e548f1ba4e804af9865de8903ae'
git-subtree-dir: doc git-subtree-mainline: bdd1dea5e21a00b6af1b0ded09e7d528485d5196 git-subtree-split: 5925379b5fb30e548f1ba4e804af9865de8903ae
-rw-r--r--doc/.gitignore40
-rwxr-xr-xdoc/10
-rwxr-xr-xdoc/b12
-rw-r--r--doc/backends/deckjs/GPL-license.txt278
-rw-r--r--doc/backends/deckjs/README.md55
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/autumn.css58
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/borland.css46
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/bw.css34
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/colorful.css61
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/default.css61
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/emacs.css61
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/friendly.css61
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/fruity.css69
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/manni.css61
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/monokai.css59
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/murphy.css61
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/native.css69
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/pastie.css60
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/perldoc.css58
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/tango.css69
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/trac.css59
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/vim.css69
-rw-r--r--doc/backends/deckjs/ad-stylesheet/pygments/vs.css33
-rw-r--r--doc/backends/deckjs/deck.js/CHANGELOG.md10
-rw-r--r--doc/backends/deckjs/deck.js/MIT-license.txt21
-rw-r--r--doc/backends/deckjs/deck.js/Makefile12
-rw-r--r--doc/backends/deckjs/deck.js/README.md60
-rw-r--r--doc/backends/deckjs/deck.js/boilerplate.html95
-rw-r--r--doc/backends/deckjs/deck.js/core/deck.core.css60
-rw-r--r--doc/backends/deckjs/deck.js/core/deck.core.js748
-rwxr-xr-xdoc/backends/deckjs/deck.js/core/deck.core.scss65
-rw-r--r--doc/backends/deckjs/deck.js/core/print.css25
-rw-r--r--doc/backends/deckjs/deck.js/core/print.scss14
-rw-r--r--doc/backends/deckjs/deck.js/extensions/deck.js-blank/README.md10
-rw-r--r--doc/backends/deckjs/deck.js/extensions/deck.js-blank/deck.blank.js33
-rw-r--r--doc/backends/deckjs/deck.js/extensions/goto/deck.goto.css36
-rw-r--r--doc/backends/deckjs/deck.js/extensions/goto/deck.goto.html7
-rw-r--r--doc/backends/deckjs/deck.js/extensions/goto/deck.goto.js190
-rwxr-xr-xdoc/backends/deckjs/deck.js/extensions/goto/deck.goto.scss39
-rw-r--r--doc/backends/deckjs/deck.js/extensions/menu/deck.menu.css45
-rw-r--r--doc/backends/deckjs/deck.js/extensions/menu/deck.menu.js225
-rwxr-xr-xdoc/backends/deckjs/deck.js/extensions/menu/deck.menu.scss55
-rw-r--r--doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.css42
-rw-r--r--doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.html5
-rw-r--r--doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.js94
-rwxr-xr-xdoc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.scss44
-rw-r--r--doc/backends/deckjs/deck.js/extensions/scale/deck.scale.css20
-rw-r--r--doc/backends/deckjs/deck.js/extensions/scale/deck.scale.js190
-rw-r--r--doc/backends/deckjs/deck.js/extensions/scale/deck.scale.scss22
-rw-r--r--doc/backends/deckjs/deck.js/extensions/split/README.md30
-rw-r--r--doc/backends/deckjs/deck.js/extensions/split/deck.split.js59
-rw-r--r--doc/backends/deckjs/deck.js/extensions/status/deck.status.css18
-rw-r--r--doc/backends/deckjs/deck.js/extensions/status/deck.status.html6
-rw-r--r--doc/backends/deckjs/deck.js/extensions/status/deck.status.js108
-rwxr-xr-xdoc/backends/deckjs/deck.js/extensions/status/deck.status.scss18
-rw-r--r--doc/backends/deckjs/deck.js/extensions/toc/deck.toc.css40
-rw-r--r--doc/backends/deckjs/deck.js/extensions/toc/deck.toc.html12
-rw-r--r--doc/backends/deckjs/deck.js/extensions/toc/deck.toc.js271
-rw-r--r--doc/backends/deckjs/deck.js/extensions/toc/deck.toc.scss54
-rw-r--r--doc/backends/deckjs/deck.js/introduction/index.html215
-rw-r--r--doc/backends/deckjs/deck.js/jquery.min.js6
-rw-r--r--doc/backends/deckjs/deck.js/modernizr.custom.js4
-rw-r--r--doc/backends/deckjs/deck.js/test/fixtures/empty.html21
-rw-r--r--doc/backends/deckjs/deck.js/test/fixtures/nesteds.html36
-rw-r--r--doc/backends/deckjs/deck.js/test/fixtures/standard.html44
-rw-r--r--doc/backends/deckjs/deck.js/test/index.html37
-rwxr-xr-xdoc/backends/deckjs/deck.js/test/lib/jasmine-html.js190
-rwxr-xr-xdoc/backends/deckjs/deck.js/test/lib/jasmine-jquery.js288
-rwxr-xr-xdoc/backends/deckjs/deck.js/test/lib/jasmine.css166
-rwxr-xr-xdoc/backends/deckjs/deck.js/test/lib/jasmine.js2477
-rwxr-xr-xdoc/backends/deckjs/deck.js/test/settings.js3
-rwxr-xr-xdoc/backends/deckjs/deck.js/test/spec.core.js527
-rw-r--r--doc/backends/deckjs/deck.js/test/spec.goto.js154
-rw-r--r--doc/backends/deckjs/deck.js/test/spec.menu.js83
-rw-r--r--doc/backends/deckjs/deck.js/test/spec.navigation.js63
-rw-r--r--doc/backends/deckjs/deck.js/test/spec.scale.js57
-rw-r--r--doc/backends/deckjs/deck.js/test/spec.status.js60
-rw-r--r--doc/backends/deckjs/deck.js/themes/style/_reset.scss300
-rw-r--r--doc/backends/deckjs/deck.js/themes/style/beamer.css286
-rw-r--r--doc/backends/deckjs/deck.js/themes/style/beamer.scss385
-rw-r--r--doc/backends/deckjs/deck.js/themes/style/neon.css421
-rw-r--r--doc/backends/deckjs/deck.js/themes/style/neon.scss148
-rw-r--r--doc/backends/deckjs/deck.js/themes/style/swiss.css404
-rw-r--r--doc/backends/deckjs/deck.js/themes/style/swiss.scss109
-rw-r--r--doc/backends/deckjs/deck.js/themes/style/web-2.0.css500
-rw-r--r--doc/backends/deckjs/deck.js/themes/style/web-2.0.scss228
-rw-r--r--doc/backends/deckjs/deck.js/themes/transition/beamer.css66
-rw-r--r--doc/backends/deckjs/deck.js/themes/transition/beamer.scss95
-rw-r--r--doc/backends/deckjs/deck.js/themes/transition/fade.css35
-rw-r--r--doc/backends/deckjs/deck.js/themes/transition/fade.scss59
-rw-r--r--doc/backends/deckjs/deck.js/themes/transition/horizontal-slide.css53
-rw-r--r--doc/backends/deckjs/deck.js/themes/transition/horizontal-slide.scss72
-rw-r--r--doc/backends/deckjs/deck.js/themes/transition/vertical-slide.css67
-rw-r--r--doc/backends/deckjs/deck.js/themes/transition/vertical-slide.scss92
-rw-r--r--doc/backends/deckjs/deckjs.conf335
-rw-r--r--doc/backends/deckjs/example/example-template.asciidoc54
-rw-r--r--doc/backends/deckjs/example/tutorial-slide.asciidoc274
-rwxr-xr-xdoc/draft_trex_stateless-docinfo.html22
-rwxr-xr-xdoc/draft_trex_stateless.asciidoc17
-rwxr-xr-xdoc/draft_trex_stateless_moved1.asciidoc28
-rwxr-xr-xdoc/images/128_nodrop.pngbin0 -> 40822 bytes
-rwxr-xr-xdoc/images/128_util.pngbin0 -> 40877 bytes
-rwxr-xr-xdoc/images/1514_nodrop.pngbin0 -> 44913 bytes
-rwxr-xr-xdoc/images/1514_util.pngbin0 -> 40567 bytes
-rwxr-xr-xdoc/images/40425209_l.jpgbin0 -> 340883 bytes
-rwxr-xr-xdoc/images/590_nodrop.pngbin0 -> 41542 bytes
-rwxr-xr-xdoc/images/590_util.pngbin0 -> 40506 bytes
-rwxr-xr-xdoc/images/64_nodrop.pngbin0 -> 40877 bytes
-rwxr-xr-xdoc/images/64_util.pngbin0 -> 41139 bytes
-rwxr-xr-xdoc/images/Intel520.pngbin0 -> 34642 bytes
-rwxr-xr-xdoc/images/T-Rex_vm.pngbin0 -> 586111 bytes
-rwxr-xr-xdoc/images/TrexConfig.pngbin0 -> 57986 bytes
-rwxr-xr-xdoc/images/TrexConfig_switch.pngbin0 -> 75038 bytes
-rwxr-xr-xdoc/images/TrexViewer.pngbin0 -> 65175 bytes
-rw-r--r--doc/images/bg4.jpgbin0 -> 231762 bytes
-rwxr-xr-xdoc/images/checkbox.jpgbin0 -> 2653 bytes
-rwxr-xr-xdoc/images/cisco.pngbin0 -> 3330 bytes
-rw-r--r--doc/images/client_clustering_topology.pngbin0 -> 204458 bytes
-rwxr-xr-xdoc/images/combo_button_choosing.jpgbin0 -> 17359 bytes
-rwxr-xr-xdoc/images/combo_button_editing.jpgbin0 -> 3029 bytes
-rwxr-xr-xdoc/images/console_link_down.pngbin0 -> 6865 bytes
-rw-r--r--doc/images/core_mask_pin.pngbin0 -> 75239 bytes
-rw-r--r--doc/images/core_mask_split.pngbin0 -> 77862 bytes
-rwxr-xr-xdoc/images/different_numa.pngbin0 -> 31915 bytes
-rwxr-xr-xdoc/images/dns_wireshark.pngbin0 -> 12271 bytes
-rwxr-xr-xdoc/images/icons/README5
-rwxr-xr-xdoc/images/icons/Thumbs.dbbin0 -> 28672 bytes
-rwxr-xr-xdoc/images/icons/callouts/1.pngbin0 -> 183 bytes
-rwxr-xr-xdoc/images/icons/callouts/10.pngbin0 -> 229 bytes
-rwxr-xr-xdoc/images/icons/callouts/11.pngbin0 -> 223 bytes
-rwxr-xr-xdoc/images/icons/callouts/12.pngbin0 -> 237 bytes
-rwxr-xr-xdoc/images/icons/callouts/13.pngbin0 -> 238 bytes
-rwxr-xr-xdoc/images/icons/callouts/14.pngbin0 -> 245 bytes
-rwxr-xr-xdoc/images/icons/callouts/15.pngbin0 -> 251 bytes
-rwxr-xr-xdoc/images/icons/callouts/2.pngbin0 -> 209 bytes
-rwxr-xr-xdoc/images/icons/callouts/3.pngbin0 -> 211 bytes
-rwxr-xr-xdoc/images/icons/callouts/4.pngbin0 -> 204 bytes
-rwxr-xr-xdoc/images/icons/callouts/5.pngbin0 -> 206 bytes
-rwxr-xr-xdoc/images/icons/callouts/6.pngbin0 -> 219 bytes
-rwxr-xr-xdoc/images/icons/callouts/7.pngbin0 -> 199 bytes
-rwxr-xr-xdoc/images/icons/callouts/8.pngbin0 -> 219 bytes
-rwxr-xr-xdoc/images/icons/callouts/9.pngbin0 -> 228 bytes
-rwxr-xr-xdoc/images/icons/callouts/Thumbs.dbbin0 -> 16896 bytes
-rwxr-xr-xdoc/images/icons/caution.pngbin0 -> 2734 bytes
-rwxr-xr-xdoc/images/icons/example.pngbin0 -> 2599 bytes
-rwxr-xr-xdoc/images/icons/home.pngbin0 -> 1340 bytes
-rwxr-xr-xdoc/images/icons/important.pngbin0 -> 2980 bytes
-rwxr-xr-xdoc/images/icons/next.pngbin0 -> 1302 bytes
-rwxr-xr-xdoc/images/icons/note.pngbin0 -> 2494 bytes
-rwxr-xr-xdoc/images/icons/prev.pngbin0 -> 1348 bytes
-rw-r--r--doc/images/icons/selected_tab_bg.pngbin0 -> 124 bytes
-rwxr-xr-xdoc/images/icons/tip.pngbin0 -> 2718 bytes
-rw-r--r--doc/images/icons/toggle.pngbin0 -> 135 bytes
-rwxr-xr-xdoc/images/icons/up.pngbin0 -> 1320 bytes
-rwxr-xr-xdoc/images/icons/warning.pngbin0 -> 3214 bytes
-rwxr-xr-xdoc/images/ip_allocation.pngbin0 -> 17687 bytes
-rwxr-xr-xdoc/images/loopback_example.pngbin0 -> 82924 bytes
-rwxr-xr-xdoc/images/loopback_right.pngbin0 -> 96274 bytes
-rwxr-xr-xdoc/images/loopback_wrong.pngbin0 -> 97046 bytes
-rwxr-xr-xdoc/images/passthrough_adding.pngbin0 -> 3678 bytes
-rwxr-xr-xdoc/images/passthrough_marking.pngbin0 -> 21375 bytes
-rwxr-xr-xdoc/images/rpc_server_big_picture.pngbin0 -> 1081192 bytes
-rw-r--r--doc/images/rpc_server_big_picture_old.pngbin0 -> 54566 bytes
-rw-r--r--doc/images/rpc_states.pngbin0 -> 58390 bytes
-rwxr-xr-xdoc/images/same_numa.pngbin0 -> 21704 bytes
-rwxr-xr-xdoc/images/scapy_json_rpc_server.pngbin0 -> 172162 bytes
-rwxr-xr-xdoc/images/sfr_profile.pngbin0 -> 16776 bytes
-rwxr-xr-xdoc/images/small.jpgbin0 -> 6943 bytes
-rwxr-xr-xdoc/images/smallnew.pngbin0 -> 292 bytes
-rw-r--r--doc/images/splitbar.pngbin0 -> 283 bytes
-rw-r--r--doc/images/stateless_objects.pngbin0 -> 20514 bytes
-rwxr-xr-xdoc/images/stateless_objects_02.pngbin0 -> 45221 bytes
-rw-r--r--doc/images/stl_arp.pngbin0 -> 39982 bytes
-rw-r--r--doc/images/stl_barrier.pngbin0 -> 26139 bytes
-rwxr-xr-xdoc/images/stl_barrier_02.pngbin0 -> 4517 bytes
-rwxr-xr-xdoc/images/stl_barrier_03.pngbin0 -> 39637 bytes
-rw-r--r--doc/images/stl_inter.pngbin0 -> 18165 bytes
-rwxr-xr-xdoc/images/stl_interleaving_01.pngbin0 -> 23097 bytes
-rwxr-xr-xdoc/images/stl_loop_count_01.pngbin0 -> 6562 bytes
-rwxr-xr-xdoc/images/stl_loop_count_01b.pngbin0 -> 5524 bytes
-rwxr-xr-xdoc/images/stl_multiple_clients_01.pngbin0 -> 42349 bytes
-rwxr-xr-xdoc/images/stl_multiple_clients_01b.pngbin0 -> 43023 bytes
-rwxr-xr-xdoc/images/stl_multiple_streams_01.pngbin0 -> 41217 bytes
-rw-r--r--doc/images/stl_null_stream.pngbin0 -> 2843 bytes
-rwxr-xr-xdoc/images/stl_null_stream_02.pngbin0 -> 9554 bytes
-rw-r--r--doc/images/stl_streams_example.pngbin0 -> 30788 bytes
-rw-r--r--doc/images/stl_streams_example.vsdbin0 -> 183296 bytes
-rwxr-xr-xdoc/images/stl_streams_example_02.pngbin0 -> 49778 bytes
-rw-r--r--doc/images/stl_tut_1.pngbin0 -> 22476 bytes
-rw-r--r--doc/images/stl_tut_12.pngbin0 -> 6751 bytes
-rw-r--r--doc/images/stl_tut_4.pngbin0 -> 17218 bytes
-rw-r--r--doc/images/stl_tut_pcap_file1.pngbin0 -> 3800 bytes
-rw-r--r--doc/images/trex-asr-setup.pngbin0 -> 42119 bytes
-rw-r--r--doc/images/trex-not-supported-setup.pngbin0 -> 59543 bytes
-rwxr-xr-xdoc/images/trex2.pngbin0 -> 59226 bytes
-rw-r--r--doc/images/trex_2.0_stateless.pngbin0 -> 1081192 bytes
-rw-r--r--doc/images/trex_2_stateless.pngbin0 -> 44004 bytes
-rwxr-xr-xdoc/images/trex_algo.pngbin0 -> 24137 bytes
-rwxr-xr-xdoc/images/trex_architecture_01.pngbin0 -> 109409 bytes
-rwxr-xr-xdoc/images/trex_auto_script.jpgbin0 -> 201947 bytes
-rwxr-xr-xdoc/images/trex_control_plane_modules.pngbin0 -> 455128 bytes
-rwxr-xr-xdoc/images/trex_desing.pngbin0 -> 17994 bytes
-rwxr-xr-xdoc/images/trex_generator_1.PNGbin0 -> 24213 bytes
-rwxr-xr-xdoc/images/trex_logo.pngbin0 -> 56958 bytes
-rwxr-xr-xdoc/images/trex_logo_64_64.pngbin0 -> 27300 bytes
-rwxr-xr-xdoc/images/trex_logo_green_small.pngbin0 -> 55947 bytes
-rw-r--r--doc/images/trex_logo_toc.pngbin0 -> 2323 bytes
-rwxr-xr-xdoc/images/trex_model.pngbin0 -> 98328 bytes
-rwxr-xr-xdoc/images/trex_motinor_config.pngbin0 -> 21573 bytes
-rwxr-xr-xdoc/images/trex_motinor_view.pngbin0 -> 168606 bytes
-rwxr-xr-xdoc/images/trex_sfr_profile.pngbin0 -> 41114 bytes
-rw-r--r--doc/images/trex_stateless_multi_user.pngbin0 -> 64465 bytes
-rwxr-xr-xdoc/images/trex_stateless_multi_user_02.pngbin0 -> 175996 bytes
-rw-r--r--doc/images/trex_stl_gui.pngbin0 -> 51441 bytes
-rwxr-xr-xdoc/images/trex_vm_bios_err.pngbin0 -> 151827 bytes
-rwxr-xr-xdoc/images/trex_vm_login.pngbin0 -> 49907 bytes
-rwxr-xr-xdoc/images/trex_vm_run.pngbin0 -> 19953 bytes
-rwxr-xr-xdoc/images/ucs200_2.pngbin0 -> 23528 bytes
-rwxr-xr-xdoc/images/vSwitch_loopback.pngbin0 -> 3578 bytes
-rwxr-xr-xdoc/images/vSwitch_main.pngbin0 -> 4880 bytes
-rwxr-xr-xdoc/images/vSwitch_networks.pngbin0 -> 2400 bytes
-rwxr-xr-xdoc/images/vm_import.pngbin0 -> 105388 bytes
-rwxr-xr-xdoc/images/vm_selection_screen.pngbin0 -> 66700 bytes
-rwxr-xr-xdoc/my_chart.js84
-rwxr-xr-xdoc/packet_builder_yaml.asciidoc674
-rwxr-xr-xdoc/release_notes.asciidoc562
-rwxr-xr-xdoc/symbols.lang5
-rwxr-xr-xdoc/trex_book-docinfo.html22
-rwxr-xr-xdoc/trex_book.asciidoc2027
-rwxr-xr-xdoc/trex_book_basic.asciidoc3306
-rwxr-xr-xdoc/trex_config.asciidoc327
-rwxr-xr-xdoc/trex_console.asciidoc596
-rwxr-xr-xdoc/trex_control_plane_design_phase1.asciidoc519
-rwxr-xr-xdoc/trex_control_plane_peek.asciidoc227
-rw-r--r--doc/trex_faq-docinfo.html22
-rw-r--r--doc/trex_faq.asciidoc444
-rwxr-xr-xdoc/trex_ga.asciidoc17
-rw-r--r--doc/trex_index.asciidoc104
-rwxr-xr-xdoc/trex_preso.asciidoc1326
-rw-r--r--doc/trex_rpc_server_spec-docinfo.html6
-rwxr-xr-xdoc/trex_rpc_server_spec.asciidoc2092
-rw-r--r--doc/trex_scapy_rpc_server-docinfo.html6
-rwxr-xr-xdoc/trex_scapy_rpc_server.asciidoc867
-rwxr-xr-xdoc/trex_stateless-docinfo.html22
-rwxr-xr-xdoc/trex_stateless.asciidoc4306
-rwxr-xr-xdoc/trex_stateless_bench.asciidoc242
-rw-r--r--doc/trex_toc.asciidoc331
-rw-r--r--doc/trex_vm_manual-docinfo.html6
-rwxr-xr-xdoc/trex_vm_manual.asciidoc304
-rwxr-xr-xdoc/visio_drawings/illustrations_stateless.vsdbin0 -> 5346816 bytes
-rw-r--r--doc/visio_drawings/stl_streams_example.vsdbin0 -> 484352 bytes
-rw-r--r--doc/visio_drawings/streams.vsdbin0 -> 63488 bytes
-rwxr-xr-xdoc/visio_drawings/trex_2.0_stateless.pngbin0 -> 1081192 bytes
-rwxr-xr-xdoc/visio_drawings/trex_2.0_stateless.vsdbin0 -> 1536000 bytes
-rwxr-xr-xdoc/vm_doc.asciidoc4
-rwxr-xr-xdoc/wafbin0 -> 90909 bytes
-rwxr-xr-xdoc/waf-1.9.3170
-rwxr-xr-xdoc/waf.css45
-rwxr-xr-xdoc/waf1.css78
-rwxr-xr-xdoc/ws_main.py1095
-rwxr-xr-xdoc/wscript68
-rwxr-xr-xdoc/yaml/headers.yaml500
262 files changed, 33107 insertions, 0 deletions
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 00000000..0a4a9da5
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1,40 @@
+# Compiled source #
+###################
+.lock-waf*
+.waf*
+linux*
+scripts/doc/*
+build/
+*.pyc
+
+# Packages #
+############
+# it's better to unpack these files and commit the raw source
+# git has its own built in compression methods
+*.7z
+*.dmg
+*.gz
+*.iso
+*.jar
+*.rar
+*.tar
+*.zip
+*.vpj
+
+# OS generated files #
+######################
+.DS_Store
+.DS_Store?
+._*
+.Trashes
+ehthumbs.db
+Thumbs.db
+
+# IDE/ Editors files #
+######################
+.idea/
+*.vpj
+*.vpw
+*.vtg
+*.vpwhist
+
diff --git a/doc/1 b/doc/1
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/doc/1
diff --git a/doc/b b/doc/b
new file mode 100755
index 00000000..58e6bddf
--- /dev/null
+++ b/doc/b
@@ -0,0 +1,12 @@
+#! /bin/bash
+
+waf=waf-1.9.3
+p2=${PYTHON:-${PYTHON2:-python2.7}}
+
+if which $p2 &> /dev/null; then
+ $p2 $waf $@
+else
+ echo "Required Python 2.7 (Asciidoc requirement)"
+ exit 1
+fi
+
diff --git a/doc/backends/deckjs/GPL-license.txt b/doc/backends/deckjs/GPL-license.txt
new file mode 100644
index 00000000..336e7bea
--- /dev/null
+++ b/doc/backends/deckjs/GPL-license.txt
@@ -0,0 +1,278 @@
+GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES. \ No newline at end of file
diff --git a/doc/backends/deckjs/README.md b/doc/backends/deckjs/README.md
new file mode 100644
index 00000000..e72c2d5b
--- /dev/null
+++ b/doc/backends/deckjs/README.md
@@ -0,0 +1,55 @@
+# Asciidoc-deck.js
+
+A Deck.js backend for asciidoc.
+
+
+## Dependencies
+
+* AsciiDoc
+* Deck.js (included in the backend package)
+
+Optional:
+
+* If you want to highlight source code, please install Pygments or source-highlight.
+
+
+## Installation
+
+Download the [backend package][deckjs] and use asciidoc to install:
+
+~~~~.bash
+asciidoc --backend install deckjs-X.Y.Z.zip
+~~~~
+
+This will install the backend to `~/.asciidoc/backend/deckjs`.
+
+You can also use this backend without installation, see the next section.
+
+
+## Usage
+
+* With deckjs backend installed, use following command to generate slides:
+
+~~~~.bash
+asciidoc -b deckjs file.asciidoc
+~~~~
+
+By default, the `linkcss` option is disabled so all the required js and css file will be embedded into the output slide. Checkout the [template file][example] for how to enable all kinds of options.
+
+* To use without Installation, you need to specify different argument:
+
+~~~~.bash
+asciidoc -f deckjs.conf file.asciidoc
+~~~~
+
+Make sure your asciidoc can properly find `deckjs.conf`. For asciidoc's configuration file loading strategy, please refer to [this guide][asc-conf-guide].
+
+Note that without installation, you also have to enable `linkcss` option. Then put `deck.js`, `ad-stylesheet` and generated slide into the same directory.
+
+
+
+[deckjs]:https://github.com/houqp/asciidoc-deckjs/downloads
+[deckjs-ext]:https://github.com/downloads/houqp/asciidoc-deckjs/deck.js.extended.zip
+[asc-conf-guide]:http://www.methods.co.nz/asciidoc/userguide.html#X27
+[example]:http://houqp.github.com/asciidoc-deckjs/example-template.asciidoc
+
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/autumn.css b/doc/backends/deckjs/ad-stylesheet/pygments/autumn.css
new file mode 100644
index 00000000..3c96f6ae
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/autumn.css
@@ -0,0 +1,58 @@
+.hll { background-color: #ffffcc }
+.c { color: #aaaaaa; font-style: italic } /* Comment */
+.err { color: #F00000; background-color: #F0A0A0 } /* Error */
+.k { color: #0000aa } /* Keyword */
+.cm { color: #aaaaaa; font-style: italic } /* Comment.Multiline */
+.cp { color: #4c8317 } /* Comment.Preproc */
+.c1 { color: #aaaaaa; font-style: italic } /* Comment.Single */
+.cs { color: #0000aa; font-style: italic } /* Comment.Special */
+.gd { color: #aa0000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #aa0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00aa00 } /* Generic.Inserted */
+.go { color: #888888 } /* Generic.Output */
+.gp { color: #555555 } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #aa0000 } /* Generic.Traceback */
+.kc { color: #0000aa } /* Keyword.Constant */
+.kd { color: #0000aa } /* Keyword.Declaration */
+.kn { color: #0000aa } /* Keyword.Namespace */
+.kp { color: #0000aa } /* Keyword.Pseudo */
+.kr { color: #0000aa } /* Keyword.Reserved */
+.kt { color: #00aaaa } /* Keyword.Type */
+.m { color: #009999 } /* Literal.Number */
+.s { color: #aa5500 } /* Literal.String */
+.na { color: #1e90ff } /* Name.Attribute */
+.nb { color: #00aaaa } /* Name.Builtin */
+.nc { color: #00aa00; text-decoration: underline } /* Name.Class */
+.no { color: #aa0000 } /* Name.Constant */
+.nd { color: #888888 } /* Name.Decorator */
+.ni { color: #800000; font-weight: bold } /* Name.Entity */
+.nf { color: #00aa00 } /* Name.Function */
+.nn { color: #00aaaa; text-decoration: underline } /* Name.Namespace */
+.nt { color: #1e90ff; font-weight: bold } /* Name.Tag */
+.nv { color: #aa0000 } /* Name.Variable */
+.ow { color: #0000aa } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #009999 } /* Literal.Number.Float */
+.mh { color: #009999 } /* Literal.Number.Hex */
+.mi { color: #009999 } /* Literal.Number.Integer */
+.mo { color: #009999 } /* Literal.Number.Oct */
+.sb { color: #aa5500 } /* Literal.String.Backtick */
+.sc { color: #aa5500 } /* Literal.String.Char */
+.sd { color: #aa5500 } /* Literal.String.Doc */
+.s2 { color: #aa5500 } /* Literal.String.Double */
+.se { color: #aa5500 } /* Literal.String.Escape */
+.sh { color: #aa5500 } /* Literal.String.Heredoc */
+.si { color: #aa5500 } /* Literal.String.Interpol */
+.sx { color: #aa5500 } /* Literal.String.Other */
+.sr { color: #009999 } /* Literal.String.Regex */
+.s1 { color: #aa5500 } /* Literal.String.Single */
+.ss { color: #0000aa } /* Literal.String.Symbol */
+.bp { color: #00aaaa } /* Name.Builtin.Pseudo */
+.vc { color: #aa0000 } /* Name.Variable.Class */
+.vg { color: #aa0000 } /* Name.Variable.Global */
+.vi { color: #aa0000 } /* Name.Variable.Instance */
+.il { color: #009999 } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/borland.css b/doc/backends/deckjs/ad-stylesheet/pygments/borland.css
new file mode 100644
index 00000000..b4999e7d
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/borland.css
@@ -0,0 +1,46 @@
+.hll { background-color: #ffffcc }
+.c { color: #008800; font-style: italic } /* Comment */
+.err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.k { color: #000080; font-weight: bold } /* Keyword */
+.cm { color: #008800; font-style: italic } /* Comment.Multiline */
+.cp { color: #008080 } /* Comment.Preproc */
+.c1 { color: #008800; font-style: italic } /* Comment.Single */
+.cs { color: #008800; font-weight: bold } /* Comment.Special */
+.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #aa0000 } /* Generic.Error */
+.gh { color: #999999 } /* Generic.Heading */
+.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+.go { color: #888888 } /* Generic.Output */
+.gp { color: #555555 } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #aaaaaa } /* Generic.Subheading */
+.gt { color: #aa0000 } /* Generic.Traceback */
+.kc { color: #000080; font-weight: bold } /* Keyword.Constant */
+.kd { color: #000080; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #000080; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #000080; font-weight: bold } /* Keyword.Pseudo */
+.kr { color: #000080; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #000080; font-weight: bold } /* Keyword.Type */
+.m { color: #0000FF } /* Literal.Number */
+.s { color: #0000FF } /* Literal.String */
+.na { color: #FF0000 } /* Name.Attribute */
+.nt { color: #000080; font-weight: bold } /* Name.Tag */
+.ow { font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #0000FF } /* Literal.Number.Float */
+.mh { color: #0000FF } /* Literal.Number.Hex */
+.mi { color: #0000FF } /* Literal.Number.Integer */
+.mo { color: #0000FF } /* Literal.Number.Oct */
+.sb { color: #0000FF } /* Literal.String.Backtick */
+.sc { color: #800080 } /* Literal.String.Char */
+.sd { color: #0000FF } /* Literal.String.Doc */
+.s2 { color: #0000FF } /* Literal.String.Double */
+.se { color: #0000FF } /* Literal.String.Escape */
+.sh { color: #0000FF } /* Literal.String.Heredoc */
+.si { color: #0000FF } /* Literal.String.Interpol */
+.sx { color: #0000FF } /* Literal.String.Other */
+.sr { color: #0000FF } /* Literal.String.Regex */
+.s1 { color: #0000FF } /* Literal.String.Single */
+.ss { color: #0000FF } /* Literal.String.Symbol */
+.il { color: #0000FF } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/bw.css b/doc/backends/deckjs/ad-stylesheet/pygments/bw.css
new file mode 100644
index 00000000..e0cfe68d
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/bw.css
@@ -0,0 +1,34 @@
+.hll { background-color: #ffffcc }
+.c { font-style: italic } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { font-weight: bold } /* Keyword */
+.cm { font-style: italic } /* Comment.Multiline */
+.c1 { font-style: italic } /* Comment.Single */
+.cs { font-style: italic } /* Comment.Special */
+.ge { font-style: italic } /* Generic.Emph */
+.gh { font-weight: bold } /* Generic.Heading */
+.gp { font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { font-weight: bold } /* Generic.Subheading */
+.kc { font-weight: bold } /* Keyword.Constant */
+.kd { font-weight: bold } /* Keyword.Declaration */
+.kn { font-weight: bold } /* Keyword.Namespace */
+.kr { font-weight: bold } /* Keyword.Reserved */
+.s { font-style: italic } /* Literal.String */
+.nc { font-weight: bold } /* Name.Class */
+.ni { font-weight: bold } /* Name.Entity */
+.ne { font-weight: bold } /* Name.Exception */
+.nn { font-weight: bold } /* Name.Namespace */
+.nt { font-weight: bold } /* Name.Tag */
+.ow { font-weight: bold } /* Operator.Word */
+.sb { font-style: italic } /* Literal.String.Backtick */
+.sc { font-style: italic } /* Literal.String.Char */
+.sd { font-style: italic } /* Literal.String.Doc */
+.s2 { font-style: italic } /* Literal.String.Double */
+.se { font-weight: bold; font-style: italic } /* Literal.String.Escape */
+.sh { font-style: italic } /* Literal.String.Heredoc */
+.si { font-weight: bold; font-style: italic } /* Literal.String.Interpol */
+.sx { font-style: italic } /* Literal.String.Other */
+.sr { font-style: italic } /* Literal.String.Regex */
+.s1 { font-style: italic } /* Literal.String.Single */
+.ss { font-style: italic } /* Literal.String.Symbol */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/colorful.css b/doc/backends/deckjs/ad-stylesheet/pygments/colorful.css
new file mode 100644
index 00000000..b0bdc4d9
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/colorful.css
@@ -0,0 +1,61 @@
+.hll { background-color: #ffffcc }
+.c { color: #808080 } /* Comment */
+.err { color: #F00000; background-color: #F0A0A0 } /* Error */
+.k { color: #008000; font-weight: bold } /* Keyword */
+.o { color: #303030 } /* Operator */
+.cm { color: #808080 } /* Comment.Multiline */
+.cp { color: #507090 } /* Comment.Preproc */
+.c1 { color: #808080 } /* Comment.Single */
+.cs { color: #cc0000; font-weight: bold } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #808080 } /* Generic.Output */
+.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #003080; font-weight: bold } /* Keyword.Pseudo */
+.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #303090; font-weight: bold } /* Keyword.Type */
+.m { color: #6000E0; font-weight: bold } /* Literal.Number */
+.s { background-color: #fff0f0 } /* Literal.String */
+.na { color: #0000C0 } /* Name.Attribute */
+.nb { color: #007020 } /* Name.Builtin */
+.nc { color: #B00060; font-weight: bold } /* Name.Class */
+.no { color: #003060; font-weight: bold } /* Name.Constant */
+.nd { color: #505050; font-weight: bold } /* Name.Decorator */
+.ni { color: #800000; font-weight: bold } /* Name.Entity */
+.ne { color: #F00000; font-weight: bold } /* Name.Exception */
+.nf { color: #0060B0; font-weight: bold } /* Name.Function */
+.nl { color: #907000; font-weight: bold } /* Name.Label */
+.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.nt { color: #007000 } /* Name.Tag */
+.nv { color: #906030 } /* Name.Variable */
+.ow { color: #000000; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #6000E0; font-weight: bold } /* Literal.Number.Float */
+.mh { color: #005080; font-weight: bold } /* Literal.Number.Hex */
+.mi { color: #0000D0; font-weight: bold } /* Literal.Number.Integer */
+.mo { color: #4000E0; font-weight: bold } /* Literal.Number.Oct */
+.sb { background-color: #fff0f0 } /* Literal.String.Backtick */
+.sc { color: #0040D0 } /* Literal.String.Char */
+.sd { color: #D04020 } /* Literal.String.Doc */
+.s2 { background-color: #fff0f0 } /* Literal.String.Double */
+.se { color: #606060; font-weight: bold; background-color: #fff0f0 } /* Literal.String.Escape */
+.sh { background-color: #fff0f0 } /* Literal.String.Heredoc */
+.si { background-color: #e0e0e0 } /* Literal.String.Interpol */
+.sx { color: #D02000; background-color: #fff0f0 } /* Literal.String.Other */
+.sr { color: #000000; background-color: #fff0ff } /* Literal.String.Regex */
+.s1 { background-color: #fff0f0 } /* Literal.String.Single */
+.ss { color: #A06000 } /* Literal.String.Symbol */
+.bp { color: #007020 } /* Name.Builtin.Pseudo */
+.vc { color: #306090 } /* Name.Variable.Class */
+.vg { color: #d07000; font-weight: bold } /* Name.Variable.Global */
+.vi { color: #3030B0 } /* Name.Variable.Instance */
+.il { color: #0000D0; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/default.css b/doc/backends/deckjs/ad-stylesheet/pygments/default.css
new file mode 100644
index 00000000..122b4294
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/default.css
@@ -0,0 +1,61 @@
+.hll { background-color: #ffffcc }
+.c { color: #408080; font-style: italic } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { color: #008000; font-weight: bold } /* Keyword */
+.o { color: #666666 } /* Operator */
+.cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.cp { color: #BC7A00 } /* Comment.Preproc */
+.c1 { color: #408080; font-style: italic } /* Comment.Single */
+.cs { color: #408080; font-style: italic } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #808080 } /* Generic.Output */
+.gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #008000 } /* Keyword.Pseudo */
+.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #B00040 } /* Keyword.Type */
+.m { color: #666666 } /* Literal.Number */
+.s { color: #BA2121 } /* Literal.String */
+.na { color: #7D9029 } /* Name.Attribute */
+.nb { color: #008000 } /* Name.Builtin */
+.nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.no { color: #880000 } /* Name.Constant */
+.nd { color: #AA22FF } /* Name.Decorator */
+.ni { color: #999999; font-weight: bold } /* Name.Entity */
+.ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.nf { color: #0000FF } /* Name.Function */
+.nl { color: #A0A000 } /* Name.Label */
+.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.nt { color: #008000; font-weight: bold } /* Name.Tag */
+.nv { color: #19177C } /* Name.Variable */
+.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #666666 } /* Literal.Number.Float */
+.mh { color: #666666 } /* Literal.Number.Hex */
+.mi { color: #666666 } /* Literal.Number.Integer */
+.mo { color: #666666 } /* Literal.Number.Oct */
+.sb { color: #BA2121 } /* Literal.String.Backtick */
+.sc { color: #BA2121 } /* Literal.String.Char */
+.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #BA2121 } /* Literal.String.Double */
+.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #BA2121 } /* Literal.String.Heredoc */
+.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.sx { color: #008000 } /* Literal.String.Other */
+.sr { color: #BB6688 } /* Literal.String.Regex */
+.s1 { color: #BA2121 } /* Literal.String.Single */
+.ss { color: #19177C } /* Literal.String.Symbol */
+.bp { color: #008000 } /* Name.Builtin.Pseudo */
+.vc { color: #19177C } /* Name.Variable.Class */
+.vg { color: #19177C } /* Name.Variable.Global */
+.vi { color: #19177C } /* Name.Variable.Instance */
+.il { color: #666666 } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/emacs.css b/doc/backends/deckjs/ad-stylesheet/pygments/emacs.css
new file mode 100644
index 00000000..ab58d9df
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/emacs.css
@@ -0,0 +1,61 @@
+.hll { background-color: #ffffcc }
+.c { color: #008800; font-style: italic } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { color: #AA22FF; font-weight: bold } /* Keyword */
+.o { color: #666666 } /* Operator */
+.cm { color: #008800; font-style: italic } /* Comment.Multiline */
+.cp { color: #008800 } /* Comment.Preproc */
+.c1 { color: #008800; font-style: italic } /* Comment.Single */
+.cs { color: #008800; font-weight: bold } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #808080 } /* Generic.Output */
+.gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */
+.kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #AA22FF; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #AA22FF } /* Keyword.Pseudo */
+.kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #00BB00; font-weight: bold } /* Keyword.Type */
+.m { color: #666666 } /* Literal.Number */
+.s { color: #BB4444 } /* Literal.String */
+.na { color: #BB4444 } /* Name.Attribute */
+.nb { color: #AA22FF } /* Name.Builtin */
+.nc { color: #0000FF } /* Name.Class */
+.no { color: #880000 } /* Name.Constant */
+.nd { color: #AA22FF } /* Name.Decorator */
+.ni { color: #999999; font-weight: bold } /* Name.Entity */
+.ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.nf { color: #00A000 } /* Name.Function */
+.nl { color: #A0A000 } /* Name.Label */
+.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.nt { color: #008000; font-weight: bold } /* Name.Tag */
+.nv { color: #B8860B } /* Name.Variable */
+.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #666666 } /* Literal.Number.Float */
+.mh { color: #666666 } /* Literal.Number.Hex */
+.mi { color: #666666 } /* Literal.Number.Integer */
+.mo { color: #666666 } /* Literal.Number.Oct */
+.sb { color: #BB4444 } /* Literal.String.Backtick */
+.sc { color: #BB4444 } /* Literal.String.Char */
+.sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #BB4444 } /* Literal.String.Double */
+.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #BB4444 } /* Literal.String.Heredoc */
+.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.sx { color: #008000 } /* Literal.String.Other */
+.sr { color: #BB6688 } /* Literal.String.Regex */
+.s1 { color: #BB4444 } /* Literal.String.Single */
+.ss { color: #B8860B } /* Literal.String.Symbol */
+.bp { color: #AA22FF } /* Name.Builtin.Pseudo */
+.vc { color: #B8860B } /* Name.Variable.Class */
+.vg { color: #B8860B } /* Name.Variable.Global */
+.vi { color: #B8860B } /* Name.Variable.Instance */
+.il { color: #666666 } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/friendly.css b/doc/backends/deckjs/ad-stylesheet/pygments/friendly.css
new file mode 100644
index 00000000..c5d10fb0
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/friendly.css
@@ -0,0 +1,61 @@
+.hll { background-color: #ffffcc }
+.c { color: #60a0b0; font-style: italic } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { color: #007020; font-weight: bold } /* Keyword */
+.o { color: #666666 } /* Operator */
+.cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */
+.cp { color: #007020 } /* Comment.Preproc */
+.c1 { color: #60a0b0; font-style: italic } /* Comment.Single */
+.cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #808080 } /* Generic.Output */
+.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #007020; font-weight: bold } /* Keyword.Constant */
+.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #007020 } /* Keyword.Pseudo */
+.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #902000 } /* Keyword.Type */
+.m { color: #40a070 } /* Literal.Number */
+.s { color: #4070a0 } /* Literal.String */
+.na { color: #4070a0 } /* Name.Attribute */
+.nb { color: #007020 } /* Name.Builtin */
+.nc { color: #0e84b5; font-weight: bold } /* Name.Class */
+.no { color: #60add5 } /* Name.Constant */
+.nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.ni { color: #d55537; font-weight: bold } /* Name.Entity */
+.ne { color: #007020 } /* Name.Exception */
+.nf { color: #06287e } /* Name.Function */
+.nl { color: #002070; font-weight: bold } /* Name.Label */
+.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.nt { color: #062873; font-weight: bold } /* Name.Tag */
+.nv { color: #bb60d5 } /* Name.Variable */
+.ow { color: #007020; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #40a070 } /* Literal.Number.Float */
+.mh { color: #40a070 } /* Literal.Number.Hex */
+.mi { color: #40a070 } /* Literal.Number.Integer */
+.mo { color: #40a070 } /* Literal.Number.Oct */
+.sb { color: #4070a0 } /* Literal.String.Backtick */
+.sc { color: #4070a0 } /* Literal.String.Char */
+.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #4070a0 } /* Literal.String.Double */
+.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #4070a0 } /* Literal.String.Heredoc */
+.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
+.sx { color: #c65d09 } /* Literal.String.Other */
+.sr { color: #235388 } /* Literal.String.Regex */
+.s1 { color: #4070a0 } /* Literal.String.Single */
+.ss { color: #517918 } /* Literal.String.Symbol */
+.bp { color: #007020 } /* Name.Builtin.Pseudo */
+.vc { color: #bb60d5 } /* Name.Variable.Class */
+.vg { color: #bb60d5 } /* Name.Variable.Global */
+.vi { color: #bb60d5 } /* Name.Variable.Instance */
+.il { color: #40a070 } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/fruity.css b/doc/backends/deckjs/ad-stylesheet/pygments/fruity.css
new file mode 100644
index 00000000..7d96f7e0
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/fruity.css
@@ -0,0 +1,69 @@
+.hll { background-color: #333333 }
+.c { color: #008800; font-style: italic; background-color: #0f140f } /* Comment */
+.err { color: #ffffff } /* Error */
+.g { color: #ffffff } /* Generic */
+.k { color: #fb660a; font-weight: bold } /* Keyword */
+.l { color: #ffffff } /* Literal */
+.n { color: #ffffff } /* Name */
+.o { color: #ffffff } /* Operator */
+.x { color: #ffffff } /* Other */
+.p { color: #ffffff } /* Punctuation */
+.cm { color: #008800; font-style: italic; background-color: #0f140f } /* Comment.Multiline */
+.cp { color: #ff0007; font-weight: bold; font-style: italic; background-color: #0f140f } /* Comment.Preproc */
+.c1 { color: #008800; font-style: italic; background-color: #0f140f } /* Comment.Single */
+.cs { color: #008800; font-style: italic; background-color: #0f140f } /* Comment.Special */
+.gd { color: #ffffff } /* Generic.Deleted */
+.ge { color: #ffffff } /* Generic.Emph */
+.gr { color: #ffffff } /* Generic.Error */
+.gh { color: #ffffff; font-weight: bold } /* Generic.Heading */
+.gi { color: #ffffff } /* Generic.Inserted */
+.go { color: #444444; background-color: #222222 } /* Generic.Output */
+.gp { color: #ffffff } /* Generic.Prompt */
+.gs { color: #ffffff } /* Generic.Strong */
+.gu { color: #ffffff; font-weight: bold } /* Generic.Subheading */
+.gt { color: #ffffff } /* Generic.Traceback */
+.kc { color: #fb660a; font-weight: bold } /* Keyword.Constant */
+.kd { color: #fb660a; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #fb660a; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #fb660a } /* Keyword.Pseudo */
+.kr { color: #fb660a; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #cdcaa9; font-weight: bold } /* Keyword.Type */
+.ld { color: #ffffff } /* Literal.Date */
+.m { color: #0086f7; font-weight: bold } /* Literal.Number */
+.s { color: #0086d2 } /* Literal.String */
+.na { color: #ff0086; font-weight: bold } /* Name.Attribute */
+.nb { color: #ffffff } /* Name.Builtin */
+.nc { color: #ffffff } /* Name.Class */
+.no { color: #0086d2 } /* Name.Constant */
+.nd { color: #ffffff } /* Name.Decorator */
+.ni { color: #ffffff } /* Name.Entity */
+.ne { color: #ffffff } /* Name.Exception */
+.nf { color: #ff0086; font-weight: bold } /* Name.Function */
+.nl { color: #ffffff } /* Name.Label */
+.nn { color: #ffffff } /* Name.Namespace */
+.nx { color: #ffffff } /* Name.Other */
+.py { color: #ffffff } /* Name.Property */
+.nt { color: #fb660a; font-weight: bold } /* Name.Tag */
+.nv { color: #fb660a } /* Name.Variable */
+.ow { color: #ffffff } /* Operator.Word */
+.w { color: #888888 } /* Text.Whitespace */
+.mf { color: #0086f7; font-weight: bold } /* Literal.Number.Float */
+.mh { color: #0086f7; font-weight: bold } /* Literal.Number.Hex */
+.mi { color: #0086f7; font-weight: bold } /* Literal.Number.Integer */
+.mo { color: #0086f7; font-weight: bold } /* Literal.Number.Oct */
+.sb { color: #0086d2 } /* Literal.String.Backtick */
+.sc { color: #0086d2 } /* Literal.String.Char */
+.sd { color: #0086d2 } /* Literal.String.Doc */
+.s2 { color: #0086d2 } /* Literal.String.Double */
+.se { color: #0086d2 } /* Literal.String.Escape */
+.sh { color: #0086d2 } /* Literal.String.Heredoc */
+.si { color: #0086d2 } /* Literal.String.Interpol */
+.sx { color: #0086d2 } /* Literal.String.Other */
+.sr { color: #0086d2 } /* Literal.String.Regex */
+.s1 { color: #0086d2 } /* Literal.String.Single */
+.ss { color: #0086d2 } /* Literal.String.Symbol */
+.bp { color: #ffffff } /* Name.Builtin.Pseudo */
+.vc { color: #fb660a } /* Name.Variable.Class */
+.vg { color: #fb660a } /* Name.Variable.Global */
+.vi { color: #fb660a } /* Name.Variable.Instance */
+.il { color: #0086f7; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/manni.css b/doc/backends/deckjs/ad-stylesheet/pygments/manni.css
new file mode 100644
index 00000000..f978b30c
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/manni.css
@@ -0,0 +1,61 @@
+.hll { background-color: #ffffcc }
+.c { color: #0099FF; font-style: italic } /* Comment */
+.err { color: #AA0000; background-color: #FFAAAA } /* Error */
+.k { color: #006699; font-weight: bold } /* Keyword */
+.o { color: #555555 } /* Operator */
+.cm { color: #0099FF; font-style: italic } /* Comment.Multiline */
+.cp { color: #009999 } /* Comment.Preproc */
+.c1 { color: #0099FF; font-style: italic } /* Comment.Single */
+.cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */
+.gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #003300; font-weight: bold } /* Generic.Heading */
+.gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */
+.go { color: #AAAAAA } /* Generic.Output */
+.gp { color: #000099; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #003300; font-weight: bold } /* Generic.Subheading */
+.gt { color: #99CC66 } /* Generic.Traceback */
+.kc { color: #006699; font-weight: bold } /* Keyword.Constant */
+.kd { color: #006699; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #006699; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #006699 } /* Keyword.Pseudo */
+.kr { color: #006699; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #007788; font-weight: bold } /* Keyword.Type */
+.m { color: #FF6600 } /* Literal.Number */
+.s { color: #CC3300 } /* Literal.String */
+.na { color: #330099 } /* Name.Attribute */
+.nb { color: #336666 } /* Name.Builtin */
+.nc { color: #00AA88; font-weight: bold } /* Name.Class */
+.no { color: #336600 } /* Name.Constant */
+.nd { color: #9999FF } /* Name.Decorator */
+.ni { color: #999999; font-weight: bold } /* Name.Entity */
+.ne { color: #CC0000; font-weight: bold } /* Name.Exception */
+.nf { color: #CC00FF } /* Name.Function */
+.nl { color: #9999FF } /* Name.Label */
+.nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */
+.nt { color: #330099; font-weight: bold } /* Name.Tag */
+.nv { color: #003333 } /* Name.Variable */
+.ow { color: #000000; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #FF6600 } /* Literal.Number.Float */
+.mh { color: #FF6600 } /* Literal.Number.Hex */
+.mi { color: #FF6600 } /* Literal.Number.Integer */
+.mo { color: #FF6600 } /* Literal.Number.Oct */
+.sb { color: #CC3300 } /* Literal.String.Backtick */
+.sc { color: #CC3300 } /* Literal.String.Char */
+.sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #CC3300 } /* Literal.String.Double */
+.se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #CC3300 } /* Literal.String.Heredoc */
+.si { color: #AA0000 } /* Literal.String.Interpol */
+.sx { color: #CC3300 } /* Literal.String.Other */
+.sr { color: #33AAAA } /* Literal.String.Regex */
+.s1 { color: #CC3300 } /* Literal.String.Single */
+.ss { color: #FFCC33 } /* Literal.String.Symbol */
+.bp { color: #336666 } /* Name.Builtin.Pseudo */
+.vc { color: #003333 } /* Name.Variable.Class */
+.vg { color: #003333 } /* Name.Variable.Global */
+.vi { color: #003333 } /* Name.Variable.Instance */
+.il { color: #FF6600 } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/monokai.css b/doc/backends/deckjs/ad-stylesheet/pygments/monokai.css
new file mode 100644
index 00000000..98f40da7
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/monokai.css
@@ -0,0 +1,59 @@
+.hll { background-color: #49483e }
+.c { color: #75715e } /* Comment */
+.err { color: #960050; background-color: #1e0010 } /* Error */
+.k { color: #66d9ef } /* Keyword */
+.l { color: #ae81ff } /* Literal */
+.n { color: #f8f8f2 } /* Name */
+.o { color: #f92672 } /* Operator */
+.p { color: #f8f8f2 } /* Punctuation */
+.cm { color: #75715e } /* Comment.Multiline */
+.cp { color: #75715e } /* Comment.Preproc */
+.c1 { color: #75715e } /* Comment.Single */
+.cs { color: #75715e } /* Comment.Special */
+.ge { font-style: italic } /* Generic.Emph */
+.gs { font-weight: bold } /* Generic.Strong */
+.kc { color: #66d9ef } /* Keyword.Constant */
+.kd { color: #66d9ef } /* Keyword.Declaration */
+.kn { color: #f92672 } /* Keyword.Namespace */
+.kp { color: #66d9ef } /* Keyword.Pseudo */
+.kr { color: #66d9ef } /* Keyword.Reserved */
+.kt { color: #66d9ef } /* Keyword.Type */
+.ld { color: #e6db74 } /* Literal.Date */
+.m { color: #ae81ff } /* Literal.Number */
+.s { color: #e6db74 } /* Literal.String */
+.na { color: #a6e22e } /* Name.Attribute */
+.nb { color: #f8f8f2 } /* Name.Builtin */
+.nc { color: #a6e22e } /* Name.Class */
+.no { color: #66d9ef } /* Name.Constant */
+.nd { color: #a6e22e } /* Name.Decorator */
+.ni { color: #f8f8f2 } /* Name.Entity */
+.ne { color: #a6e22e } /* Name.Exception */
+.nf { color: #a6e22e } /* Name.Function */
+.nl { color: #f8f8f2 } /* Name.Label */
+.nn { color: #f8f8f2 } /* Name.Namespace */
+.nx { color: #a6e22e } /* Name.Other */
+.py { color: #f8f8f2 } /* Name.Property */
+.nt { color: #f92672 } /* Name.Tag */
+.nv { color: #f8f8f2 } /* Name.Variable */
+.ow { color: #f92672 } /* Operator.Word */
+.w { color: #f8f8f2 } /* Text.Whitespace */
+.mf { color: #ae81ff } /* Literal.Number.Float */
+.mh { color: #ae81ff } /* Literal.Number.Hex */
+.mi { color: #ae81ff } /* Literal.Number.Integer */
+.mo { color: #ae81ff } /* Literal.Number.Oct */
+.sb { color: #e6db74 } /* Literal.String.Backtick */
+.sc { color: #e6db74 } /* Literal.String.Char */
+.sd { color: #e6db74 } /* Literal.String.Doc */
+.s2 { color: #e6db74 } /* Literal.String.Double */
+.se { color: #ae81ff } /* Literal.String.Escape */
+.sh { color: #e6db74 } /* Literal.String.Heredoc */
+.si { color: #e6db74 } /* Literal.String.Interpol */
+.sx { color: #e6db74 } /* Literal.String.Other */
+.sr { color: #e6db74 } /* Literal.String.Regex */
+.s1 { color: #e6db74 } /* Literal.String.Single */
+.ss { color: #e6db74 } /* Literal.String.Symbol */
+.bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
+.vc { color: #f8f8f2 } /* Name.Variable.Class */
+.vg { color: #f8f8f2 } /* Name.Variable.Global */
+.vi { color: #f8f8f2 } /* Name.Variable.Instance */
+.il { color: #ae81ff } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/murphy.css b/doc/backends/deckjs/ad-stylesheet/pygments/murphy.css
new file mode 100644
index 00000000..ecae07cc
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/murphy.css
@@ -0,0 +1,61 @@
+.hll { background-color: #ffffcc }
+.c { color: #606060; font-style: italic } /* Comment */
+.err { color: #F00000; background-color: #F0A0A0 } /* Error */
+.k { color: #208090; font-weight: bold } /* Keyword */
+.o { color: #303030 } /* Operator */
+.cm { color: #606060; font-style: italic } /* Comment.Multiline */
+.cp { color: #507090 } /* Comment.Preproc */
+.c1 { color: #606060; font-style: italic } /* Comment.Single */
+.cs { color: #c00000; font-weight: bold; font-style: italic } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #808080 } /* Generic.Output */
+.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #208090; font-weight: bold } /* Keyword.Constant */
+.kd { color: #208090; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #208090; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #0080f0; font-weight: bold } /* Keyword.Pseudo */
+.kr { color: #208090; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #6060f0; font-weight: bold } /* Keyword.Type */
+.m { color: #6000E0; font-weight: bold } /* Literal.Number */
+.s { background-color: #e0e0ff } /* Literal.String */
+.na { color: #000070 } /* Name.Attribute */
+.nb { color: #007020 } /* Name.Builtin */
+.nc { color: #e090e0; font-weight: bold } /* Name.Class */
+.no { color: #50e0d0; font-weight: bold } /* Name.Constant */
+.nd { color: #505050; font-weight: bold } /* Name.Decorator */
+.ni { color: #800000 } /* Name.Entity */
+.ne { color: #F00000; font-weight: bold } /* Name.Exception */
+.nf { color: #50e0d0; font-weight: bold } /* Name.Function */
+.nl { color: #907000; font-weight: bold } /* Name.Label */
+.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.nt { color: #007000 } /* Name.Tag */
+.nv { color: #003060 } /* Name.Variable */
+.ow { color: #000000; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #6000E0; font-weight: bold } /* Literal.Number.Float */
+.mh { color: #005080; font-weight: bold } /* Literal.Number.Hex */
+.mi { color: #6060f0; font-weight: bold } /* Literal.Number.Integer */
+.mo { color: #4000E0; font-weight: bold } /* Literal.Number.Oct */
+.sb { background-color: #e0e0ff } /* Literal.String.Backtick */
+.sc { color: #8080F0 } /* Literal.String.Char */
+.sd { color: #D04020 } /* Literal.String.Doc */
+.s2 { background-color: #e0e0ff } /* Literal.String.Double */
+.se { color: #606060; font-weight: bold; background-color: #e0e0ff } /* Literal.String.Escape */
+.sh { background-color: #e0e0ff } /* Literal.String.Heredoc */
+.si { background-color: #e0e0e0 } /* Literal.String.Interpol */
+.sx { color: #f08080; background-color: #e0e0ff } /* Literal.String.Other */
+.sr { color: #000000; background-color: #e0e0ff } /* Literal.String.Regex */
+.s1 { background-color: #e0e0ff } /* Literal.String.Single */
+.ss { color: #f0c080 } /* Literal.String.Symbol */
+.bp { color: #007020 } /* Name.Builtin.Pseudo */
+.vc { color: #c0c0f0 } /* Name.Variable.Class */
+.vg { color: #f08040 } /* Name.Variable.Global */
+.vi { color: #a0a0f0 } /* Name.Variable.Instance */
+.il { color: #6060f0; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/native.css b/doc/backends/deckjs/ad-stylesheet/pygments/native.css
new file mode 100644
index 00000000..bffc5c9b
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/native.css
@@ -0,0 +1,69 @@
+.hll { background-color: #404040 }
+.c { color: #999999; font-style: italic } /* Comment */
+.err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.g { color: #d0d0d0 } /* Generic */
+.k { color: #6ab825; font-weight: bold } /* Keyword */
+.l { color: #d0d0d0 } /* Literal */
+.n { color: #d0d0d0 } /* Name */
+.o { color: #d0d0d0 } /* Operator */
+.x { color: #d0d0d0 } /* Other */
+.p { color: #d0d0d0 } /* Punctuation */
+.cm { color: #999999; font-style: italic } /* Comment.Multiline */
+.cp { color: #cd2828; font-weight: bold } /* Comment.Preproc */
+.c1 { color: #999999; font-style: italic } /* Comment.Single */
+.cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */
+.gd { color: #d22323 } /* Generic.Deleted */
+.ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */
+.gr { color: #d22323 } /* Generic.Error */
+.gh { color: #ffffff; font-weight: bold } /* Generic.Heading */
+.gi { color: #589819 } /* Generic.Inserted */
+.go { color: #cccccc } /* Generic.Output */
+.gp { color: #aaaaaa } /* Generic.Prompt */
+.gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */
+.gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */
+.gt { color: #d22323 } /* Generic.Traceback */
+.kc { color: #6ab825; font-weight: bold } /* Keyword.Constant */
+.kd { color: #6ab825; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #6ab825; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #6ab825 } /* Keyword.Pseudo */
+.kr { color: #6ab825; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #6ab825; font-weight: bold } /* Keyword.Type */
+.ld { color: #d0d0d0 } /* Literal.Date */
+.m { color: #3677a9 } /* Literal.Number */
+.s { color: #ed9d13 } /* Literal.String */
+.na { color: #bbbbbb } /* Name.Attribute */
+.nb { color: #24909d } /* Name.Builtin */
+.nc { color: #447fcf; text-decoration: underline } /* Name.Class */
+.no { color: #40ffff } /* Name.Constant */
+.nd { color: #ffa500 } /* Name.Decorator */
+.ni { color: #d0d0d0 } /* Name.Entity */
+.ne { color: #bbbbbb } /* Name.Exception */
+.nf { color: #447fcf } /* Name.Function */
+.nl { color: #d0d0d0 } /* Name.Label */
+.nn { color: #447fcf; text-decoration: underline } /* Name.Namespace */
+.nx { color: #d0d0d0 } /* Name.Other */
+.py { color: #d0d0d0 } /* Name.Property */
+.nt { color: #6ab825; font-weight: bold } /* Name.Tag */
+.nv { color: #40ffff } /* Name.Variable */
+.ow { color: #6ab825; font-weight: bold } /* Operator.Word */
+.w { color: #666666 } /* Text.Whitespace */
+.mf { color: #3677a9 } /* Literal.Number.Float */
+.mh { color: #3677a9 } /* Literal.Number.Hex */
+.mi { color: #3677a9 } /* Literal.Number.Integer */
+.mo { color: #3677a9 } /* Literal.Number.Oct */
+.sb { color: #ed9d13 } /* Literal.String.Backtick */
+.sc { color: #ed9d13 } /* Literal.String.Char */
+.sd { color: #ed9d13 } /* Literal.String.Doc */
+.s2 { color: #ed9d13 } /* Literal.String.Double */
+.se { color: #ed9d13 } /* Literal.String.Escape */
+.sh { color: #ed9d13 } /* Literal.String.Heredoc */
+.si { color: #ed9d13 } /* Literal.String.Interpol */
+.sx { color: #ffa500 } /* Literal.String.Other */
+.sr { color: #ed9d13 } /* Literal.String.Regex */
+.s1 { color: #ed9d13 } /* Literal.String.Single */
+.ss { color: #ed9d13 } /* Literal.String.Symbol */
+.bp { color: #24909d } /* Name.Builtin.Pseudo */
+.vc { color: #40ffff } /* Name.Variable.Class */
+.vg { color: #40ffff } /* Name.Variable.Global */
+.vi { color: #40ffff } /* Name.Variable.Instance */
+.il { color: #3677a9 } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/pastie.css b/doc/backends/deckjs/ad-stylesheet/pygments/pastie.css
new file mode 100644
index 00000000..5cea4ab7
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/pastie.css
@@ -0,0 +1,60 @@
+.hll { background-color: #ffffcc }
+.c { color: #888888 } /* Comment */
+.err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.k { color: #008800; font-weight: bold } /* Keyword */
+.cm { color: #888888 } /* Comment.Multiline */
+.cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
+.c1 { color: #888888 } /* Comment.Single */
+.cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
+.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #aa0000 } /* Generic.Error */
+.gh { color: #303030 } /* Generic.Heading */
+.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+.go { color: #888888 } /* Generic.Output */
+.gp { color: #555555 } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #606060 } /* Generic.Subheading */
+.gt { color: #aa0000 } /* Generic.Traceback */
+.kc { color: #008800; font-weight: bold } /* Keyword.Constant */
+.kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #008800 } /* Keyword.Pseudo */
+.kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #888888; font-weight: bold } /* Keyword.Type */
+.m { color: #0000DD; font-weight: bold } /* Literal.Number */
+.s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
+.na { color: #336699 } /* Name.Attribute */
+.nb { color: #003388 } /* Name.Builtin */
+.nc { color: #bb0066; font-weight: bold } /* Name.Class */
+.no { color: #003366; font-weight: bold } /* Name.Constant */
+.nd { color: #555555 } /* Name.Decorator */
+.ne { color: #bb0066; font-weight: bold } /* Name.Exception */
+.nf { color: #0066bb; font-weight: bold } /* Name.Function */
+.nl { color: #336699; font-style: italic } /* Name.Label */
+.nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
+.py { color: #336699; font-weight: bold } /* Name.Property */
+.nt { color: #bb0066; font-weight: bold } /* Name.Tag */
+.nv { color: #336699 } /* Name.Variable */
+.ow { color: #008800 } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
+.mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
+.mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
+.mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
+.sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
+.sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
+.sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
+.s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
+.se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
+.sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
+.si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
+.sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
+.sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
+.s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
+.ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
+.bp { color: #003388 } /* Name.Builtin.Pseudo */
+.vc { color: #336699 } /* Name.Variable.Class */
+.vg { color: #dd7700 } /* Name.Variable.Global */
+.vi { color: #3333bb } /* Name.Variable.Instance */
+.il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/perldoc.css b/doc/backends/deckjs/ad-stylesheet/pygments/perldoc.css
new file mode 100644
index 00000000..4b1ef72f
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/perldoc.css
@@ -0,0 +1,58 @@
+.hll { background-color: #ffffcc }
+.c { color: #228B22 } /* Comment */
+.err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.k { color: #8B008B; font-weight: bold } /* Keyword */
+.cm { color: #228B22 } /* Comment.Multiline */
+.cp { color: #1e889b } /* Comment.Preproc */
+.c1 { color: #228B22 } /* Comment.Single */
+.cs { color: #8B008B; font-weight: bold } /* Comment.Special */
+.gd { color: #aa0000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #aa0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00aa00 } /* Generic.Inserted */
+.go { color: #888888 } /* Generic.Output */
+.gp { color: #555555 } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #aa0000 } /* Generic.Traceback */
+.kc { color: #8B008B; font-weight: bold } /* Keyword.Constant */
+.kd { color: #8B008B; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #8B008B; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #8B008B; font-weight: bold } /* Keyword.Pseudo */
+.kr { color: #8B008B; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #a7a7a7; font-weight: bold } /* Keyword.Type */
+.m { color: #B452CD } /* Literal.Number */
+.s { color: #CD5555 } /* Literal.String */
+.na { color: #658b00 } /* Name.Attribute */
+.nb { color: #658b00 } /* Name.Builtin */
+.nc { color: #008b45; font-weight: bold } /* Name.Class */
+.no { color: #00688B } /* Name.Constant */
+.nd { color: #707a7c } /* Name.Decorator */
+.ne { color: #008b45; font-weight: bold } /* Name.Exception */
+.nf { color: #008b45 } /* Name.Function */
+.nn { color: #008b45; text-decoration: underline } /* Name.Namespace */
+.nt { color: #8B008B; font-weight: bold } /* Name.Tag */
+.nv { color: #00688B } /* Name.Variable */
+.ow { color: #8B008B } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #B452CD } /* Literal.Number.Float */
+.mh { color: #B452CD } /* Literal.Number.Hex */
+.mi { color: #B452CD } /* Literal.Number.Integer */
+.mo { color: #B452CD } /* Literal.Number.Oct */
+.sb { color: #CD5555 } /* Literal.String.Backtick */
+.sc { color: #CD5555 } /* Literal.String.Char */
+.sd { color: #CD5555 } /* Literal.String.Doc */
+.s2 { color: #CD5555 } /* Literal.String.Double */
+.se { color: #CD5555 } /* Literal.String.Escape */
+.sh { color: #1c7e71; font-style: italic } /* Literal.String.Heredoc */
+.si { color: #CD5555 } /* Literal.String.Interpol */
+.sx { color: #cb6c20 } /* Literal.String.Other */
+.sr { color: #1c7e71 } /* Literal.String.Regex */
+.s1 { color: #CD5555 } /* Literal.String.Single */
+.ss { color: #CD5555 } /* Literal.String.Symbol */
+.bp { color: #658b00 } /* Name.Builtin.Pseudo */
+.vc { color: #00688B } /* Name.Variable.Class */
+.vg { color: #00688B } /* Name.Variable.Global */
+.vi { color: #00688B } /* Name.Variable.Instance */
+.il { color: #B452CD } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/tango.css b/doc/backends/deckjs/ad-stylesheet/pygments/tango.css
new file mode 100644
index 00000000..45bae6e0
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/tango.css
@@ -0,0 +1,69 @@
+.hll { background-color: #ffffcc }
+.c { color: #8f5902; font-style: italic } /* Comment */
+.err { color: #a40000; border: 1px solid #ef2929 } /* Error */
+.g { color: #000000 } /* Generic */
+.k { color: #204a87; font-weight: bold } /* Keyword */
+.l { color: #000000 } /* Literal */
+.n { color: #000000 } /* Name */
+.o { color: #ce5c00; font-weight: bold } /* Operator */
+.x { color: #000000 } /* Other */
+.p { color: #000000; font-weight: bold } /* Punctuation */
+.cm { color: #8f5902; font-style: italic } /* Comment.Multiline */
+.cp { color: #8f5902; font-style: italic } /* Comment.Preproc */
+.c1 { color: #8f5902; font-style: italic } /* Comment.Single */
+.cs { color: #8f5902; font-style: italic } /* Comment.Special */
+.gd { color: #a40000 } /* Generic.Deleted */
+.ge { color: #000000; font-style: italic } /* Generic.Emph */
+.gr { color: #ef2929 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #000000; font-style: italic } /* Generic.Output */
+.gp { color: #8f5902 } /* Generic.Prompt */
+.gs { color: #000000; font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #a40000; font-weight: bold } /* Generic.Traceback */
+.kc { color: #204a87; font-weight: bold } /* Keyword.Constant */
+.kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */
+.kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #204a87; font-weight: bold } /* Keyword.Type */
+.ld { color: #000000 } /* Literal.Date */
+.m { color: #0000cf; font-weight: bold } /* Literal.Number */
+.s { color: #4e9a06 } /* Literal.String */
+.na { color: #c4a000 } /* Name.Attribute */
+.nb { color: #204a87 } /* Name.Builtin */
+.nc { color: #000000 } /* Name.Class */
+.no { color: #000000 } /* Name.Constant */
+.nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */
+.ni { color: #ce5c00 } /* Name.Entity */
+.ne { color: #cc0000; font-weight: bold } /* Name.Exception */
+.nf { color: #000000 } /* Name.Function */
+.nl { color: #f57900 } /* Name.Label */
+.nn { color: #000000 } /* Name.Namespace */
+.nx { color: #000000 } /* Name.Other */
+.py { color: #000000 } /* Name.Property */
+.nt { color: #204a87; font-weight: bold } /* Name.Tag */
+.nv { color: #000000 } /* Name.Variable */
+.ow { color: #204a87; font-weight: bold } /* Operator.Word */
+.w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */
+.mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */
+.mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */
+.mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */
+.mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */
+.sb { color: #4e9a06 } /* Literal.String.Backtick */
+.sc { color: #4e9a06 } /* Literal.String.Char */
+.sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #4e9a06 } /* Literal.String.Double */
+.se { color: #4e9a06 } /* Literal.String.Escape */
+.sh { color: #4e9a06 } /* Literal.String.Heredoc */
+.si { color: #4e9a06 } /* Literal.String.Interpol */
+.sx { color: #4e9a06 } /* Literal.String.Other */
+.sr { color: #4e9a06 } /* Literal.String.Regex */
+.s1 { color: #4e9a06 } /* Literal.String.Single */
+.ss { color: #4e9a06 } /* Literal.String.Symbol */
+.bp { color: #3465a4 } /* Name.Builtin.Pseudo */
+.vc { color: #000000 } /* Name.Variable.Class */
+.vg { color: #000000 } /* Name.Variable.Global */
+.vi { color: #000000 } /* Name.Variable.Instance */
+.il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/trac.css b/doc/backends/deckjs/ad-stylesheet/pygments/trac.css
new file mode 100644
index 00000000..6f4f6c86
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/trac.css
@@ -0,0 +1,59 @@
+.hll { background-color: #ffffcc }
+.c { color: #999988; font-style: italic } /* Comment */
+.err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.k { font-weight: bold } /* Keyword */
+.o { font-weight: bold } /* Operator */
+.cm { color: #999988; font-style: italic } /* Comment.Multiline */
+.cp { color: #999999; font-weight: bold } /* Comment.Preproc */
+.c1 { color: #999988; font-style: italic } /* Comment.Single */
+.cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
+.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #aa0000 } /* Generic.Error */
+.gh { color: #999999 } /* Generic.Heading */
+.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+.go { color: #888888 } /* Generic.Output */
+.gp { color: #555555 } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #aaaaaa } /* Generic.Subheading */
+.gt { color: #aa0000 } /* Generic.Traceback */
+.kc { font-weight: bold } /* Keyword.Constant */
+.kd { font-weight: bold } /* Keyword.Declaration */
+.kn { font-weight: bold } /* Keyword.Namespace */
+.kp { font-weight: bold } /* Keyword.Pseudo */
+.kr { font-weight: bold } /* Keyword.Reserved */
+.kt { color: #445588; font-weight: bold } /* Keyword.Type */
+.m { color: #009999 } /* Literal.Number */
+.s { color: #bb8844 } /* Literal.String */
+.na { color: #008080 } /* Name.Attribute */
+.nb { color: #999999 } /* Name.Builtin */
+.nc { color: #445588; font-weight: bold } /* Name.Class */
+.no { color: #008080 } /* Name.Constant */
+.ni { color: #800080 } /* Name.Entity */
+.ne { color: #990000; font-weight: bold } /* Name.Exception */
+.nf { color: #990000; font-weight: bold } /* Name.Function */
+.nn { color: #555555 } /* Name.Namespace */
+.nt { color: #000080 } /* Name.Tag */
+.nv { color: #008080 } /* Name.Variable */
+.ow { font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #009999 } /* Literal.Number.Float */
+.mh { color: #009999 } /* Literal.Number.Hex */
+.mi { color: #009999 } /* Literal.Number.Integer */
+.mo { color: #009999 } /* Literal.Number.Oct */
+.sb { color: #bb8844 } /* Literal.String.Backtick */
+.sc { color: #bb8844 } /* Literal.String.Char */
+.sd { color: #bb8844 } /* Literal.String.Doc */
+.s2 { color: #bb8844 } /* Literal.String.Double */
+.se { color: #bb8844 } /* Literal.String.Escape */
+.sh { color: #bb8844 } /* Literal.String.Heredoc */
+.si { color: #bb8844 } /* Literal.String.Interpol */
+.sx { color: #bb8844 } /* Literal.String.Other */
+.sr { color: #808000 } /* Literal.String.Regex */
+.s1 { color: #bb8844 } /* Literal.String.Single */
+.ss { color: #bb8844 } /* Literal.String.Symbol */
+.bp { color: #999999 } /* Name.Builtin.Pseudo */
+.vc { color: #008080 } /* Name.Variable.Class */
+.vg { color: #008080 } /* Name.Variable.Global */
+.vi { color: #008080 } /* Name.Variable.Instance */
+.il { color: #009999 } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/vim.css b/doc/backends/deckjs/ad-stylesheet/pygments/vim.css
new file mode 100644
index 00000000..fda8b184
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/vim.css
@@ -0,0 +1,69 @@
+.hll { background-color: #222222 }
+.c { color: #000080 } /* Comment */
+.err { color: #cccccc; border: 1px solid #FF0000 } /* Error */
+.g { color: #cccccc } /* Generic */
+.k { color: #cdcd00 } /* Keyword */
+.l { color: #cccccc } /* Literal */
+.n { color: #cccccc } /* Name */
+.o { color: #3399cc } /* Operator */
+.x { color: #cccccc } /* Other */
+.p { color: #cccccc } /* Punctuation */
+.cm { color: #000080 } /* Comment.Multiline */
+.cp { color: #000080 } /* Comment.Preproc */
+.c1 { color: #000080 } /* Comment.Single */
+.cs { color: #cd0000; font-weight: bold } /* Comment.Special */
+.gd { color: #cd0000 } /* Generic.Deleted */
+.ge { color: #cccccc; font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00cd00 } /* Generic.Inserted */
+.go { color: #808080 } /* Generic.Output */
+.gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.gs { color: #cccccc; font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #cdcd00 } /* Keyword.Constant */
+.kd { color: #00cd00 } /* Keyword.Declaration */
+.kn { color: #cd00cd } /* Keyword.Namespace */
+.kp { color: #cdcd00 } /* Keyword.Pseudo */
+.kr { color: #cdcd00 } /* Keyword.Reserved */
+.kt { color: #00cd00 } /* Keyword.Type */
+.ld { color: #cccccc } /* Literal.Date */
+.m { color: #cd00cd } /* Literal.Number */
+.s { color: #cd0000 } /* Literal.String */
+.na { color: #cccccc } /* Name.Attribute */
+.nb { color: #cd00cd } /* Name.Builtin */
+.nc { color: #00cdcd } /* Name.Class */
+.no { color: #cccccc } /* Name.Constant */
+.nd { color: #cccccc } /* Name.Decorator */
+.ni { color: #cccccc } /* Name.Entity */
+.ne { color: #666699; font-weight: bold } /* Name.Exception */
+.nf { color: #cccccc } /* Name.Function */
+.nl { color: #cccccc } /* Name.Label */
+.nn { color: #cccccc } /* Name.Namespace */
+.nx { color: #cccccc } /* Name.Other */
+.py { color: #cccccc } /* Name.Property */
+.nt { color: #cccccc } /* Name.Tag */
+.nv { color: #00cdcd } /* Name.Variable */
+.ow { color: #cdcd00 } /* Operator.Word */
+.w { color: #cccccc } /* Text.Whitespace */
+.mf { color: #cd00cd } /* Literal.Number.Float */
+.mh { color: #cd00cd } /* Literal.Number.Hex */
+.mi { color: #cd00cd } /* Literal.Number.Integer */
+.mo { color: #cd00cd } /* Literal.Number.Oct */
+.sb { color: #cd0000 } /* Literal.String.Backtick */
+.sc { color: #cd0000 } /* Literal.String.Char */
+.sd { color: #cd0000 } /* Literal.String.Doc */
+.s2 { color: #cd0000 } /* Literal.String.Double */
+.se { color: #cd0000 } /* Literal.String.Escape */
+.sh { color: #cd0000 } /* Literal.String.Heredoc */
+.si { color: #cd0000 } /* Literal.String.Interpol */
+.sx { color: #cd0000 } /* Literal.String.Other */
+.sr { color: #cd0000 } /* Literal.String.Regex */
+.s1 { color: #cd0000 } /* Literal.String.Single */
+.ss { color: #cd0000 } /* Literal.String.Symbol */
+.bp { color: #cd00cd } /* Name.Builtin.Pseudo */
+.vc { color: #00cdcd } /* Name.Variable.Class */
+.vg { color: #00cdcd } /* Name.Variable.Global */
+.vi { color: #00cdcd } /* Name.Variable.Instance */
+.il { color: #cd00cd } /* Literal.Number.Integer.Long */
diff --git a/doc/backends/deckjs/ad-stylesheet/pygments/vs.css b/doc/backends/deckjs/ad-stylesheet/pygments/vs.css
new file mode 100644
index 00000000..13cebf50
--- /dev/null
+++ b/doc/backends/deckjs/ad-stylesheet/pygments/vs.css
@@ -0,0 +1,33 @@
+.hll { background-color: #ffffcc }
+.c { color: #008000 } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { color: #0000ff } /* Keyword */
+.cm { color: #008000 } /* Comment.Multiline */
+.cp { color: #0000ff } /* Comment.Preproc */
+.c1 { color: #008000 } /* Comment.Single */
+.cs { color: #008000 } /* Comment.Special */
+.ge { font-style: italic } /* Generic.Emph */
+.gh { font-weight: bold } /* Generic.Heading */
+.gp { font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { font-weight: bold } /* Generic.Subheading */
+.kc { color: #0000ff } /* Keyword.Constant */
+.kd { color: #0000ff } /* Keyword.Declaration */
+.kn { color: #0000ff } /* Keyword.Namespace */
+.kp { color: #0000ff } /* Keyword.Pseudo */
+.kr { color: #0000ff } /* Keyword.Reserved */
+.kt { color: #2b91af } /* Keyword.Type */
+.s { color: #a31515 } /* Literal.String */
+.nc { color: #2b91af } /* Name.Class */
+.ow { color: #0000ff } /* Operator.Word */
+.sb { color: #a31515 } /* Literal.String.Backtick */
+.sc { color: #a31515 } /* Literal.String.Char */
+.sd { color: #a31515 } /* Literal.String.Doc */
+.s2 { color: #a31515 } /* Literal.String.Double */
+.se { color: #a31515 } /* Literal.String.Escape */
+.sh { color: #a31515 } /* Literal.String.Heredoc */
+.si { color: #a31515 } /* Literal.String.Interpol */
+.sx { color: #a31515 } /* Literal.String.Other */
+.sr { color: #a31515 } /* Literal.String.Regex */
+.s1 { color: #a31515 } /* Literal.String.Single */
+.ss { color: #a31515 } /* Literal.String.Symbol */
diff --git a/doc/backends/deckjs/deck.js/CHANGELOG.md b/doc/backends/deckjs/deck.js/CHANGELOG.md
new file mode 100644
index 00000000..6645baa5
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/CHANGELOG.md
@@ -0,0 +1,10 @@
+# Changelog
+
+## v1.1.0
+
+- Expand `beforeInit` event to allow halting of init event.
+- Create alternative init signature with single options object using new `options.selectors.slides` option.
+- Added methods `getTopLevelSlides` and `getNestedSlides`.
+- Integrated hash plugin into core.
+- Allow for touch swiping to be axis specific or disabled.
+- Include ARIA attribute considerations in core and extensions.
diff --git a/doc/backends/deckjs/deck.js/MIT-license.txt b/doc/backends/deckjs/deck.js/MIT-license.txt
new file mode 100644
index 00000000..3eec2860
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/MIT-license.txt
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2011-2014 Caleb Troughton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/doc/backends/deckjs/deck.js/Makefile b/doc/backends/deckjs/deck.js/Makefile
new file mode 100644
index 00000000..04076c2e
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/Makefile
@@ -0,0 +1,12 @@
+SASSOPTS=--scss --style expanded
+
+default: generate
+
+generate:
+ sass --update ${SASSOPTS} .
+
+force:
+ sass --update ${SASSOPTS} --force .
+
+watch:
+ sass --watch ${SASSOPTS} .
diff --git a/doc/backends/deckjs/deck.js/README.md b/doc/backends/deckjs/deck.js/README.md
new file mode 100644
index 00000000..31931b48
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/README.md
@@ -0,0 +1,60 @@
+#deck.js
+
+A JavaScript library for building modern HTML presentations. deck.js is flexible enough to let advanced CSS and JavaScript authors craft highly customized decks, but also provides templates and themes for the HTML novice to build a standard slideshow.
+
+## Quick Start
+
+This repository includes a `boilerplate.html` as a starting point, with all the extensions included. Just [download it](https://github.com/imakewebthings/deck.js/archive/latest.zip), open `boilerplate.html`, and start editing your slides.
+
+## Documentation
+
+Check out the [documentation page](http://imakewebthings.github.com/deck.js/docs) for more information on the methods, events, and options available in core and all the included extensions. A sample standard slide deck is included in the package under the `introduction` folder. You can also [view that sample deck](http://imakewebthings.github.com/deck.js/introduction) online to play with the available style and transition themes.
+
+## Extensions, Themes, and Related Projects
+
+Take a look at [the wiki](https://github.com/imakewebthings/deck.js/wiki) for lists of extensions, themes, and other related goodies. If you have a publicly available project of your own, feel free to add to the list.
+
+## Dependencies (included in this repository)
+
+- [jQuery](http://jquery.com)
+- [Modernizr](http://modernizr.com)
+
+## Tests & Support
+
+Unit tests are written with [Jasmine](http://pivotal.github.com/jasmine/) and [jasmine-jquery](https://github.com/velesin/jasmine-jquery). You can [run them here](http://imakewebthings.github.com/deck.js/test).
+
+deck.js has been tested with jQuery 1.6+ and works in IE7+, Chrome, FF, Safari, and Opera. The more capable browsers receive greater enhancements, but a basic cutaway slideshow will work for all browsers listed above. Please don't give your presentations in IE6.
+
+For any questions or general discussion about deck.js please direct your attention to the [mailing list](http://groups.google.com/group/deckjs) (uses Google groups.) If you would like to report a bug, please see the [issues page](https://github.com/imakewebthings/deck.js/issues).
+
+## Printing
+
+Core includes stripped down black and white print styles for the standard slide template that is suitable for handouts.
+
+## Awesome Contributors
+
+- [jbuck](https://github.com/jbuck)
+- [cykod](https://github.com/cykod)
+- [dougireton](https://github.com/dougireton)
+- [awirick](https://github.com/awirick)
+- Daniel Knittl-Frank
+- [alexch](https://github.com/alexch)
+- [twitwi](https://github.com/twitwi)
+
+If you would like to contribute a patch to deck.js please do as much as you can of the following:
+
+- Add or amend Jasmine tests.
+- Add inline documentation.
+- If the standard snippet of an extension changes, please change it in both the introduction deck and the snippet html in the extension folder.
+- If the API changes, it would be awesome to receive a parallel pull request to the gh-pages branch which updates the public-facing documentation.
+
+## License
+
+Copyright (c) 2011-2014 Caleb Troughton
+
+Licensed under the [MIT license](https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt)
+
+## Donations
+
+[![Gittip donate
+button](http://img.shields.io/gittip/imakewebthings.png)](https://www.gittip.com/imakewebthings/ "Donate weekly to this project using Gittip")
diff --git a/doc/backends/deckjs/deck.js/boilerplate.html b/doc/backends/deckjs/deck.js/boilerplate.html
new file mode 100644
index 00000000..b901d245
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/boilerplate.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=1024, user-scalable=no">
+
+ <title>Your deck.js Presentation</title>
+
+ <!-- Required stylesheet -->
+ <link rel="stylesheet" media="screen" href="core/deck.core.css">
+
+ <!-- Extension CSS files go here. Remove or add as needed. -->
+ <link rel="stylesheet" media="screen" href="extensions/goto/deck.goto.css">
+ <link rel="stylesheet" media="screen" href="extensions/menu/deck.menu.css">
+ <link rel="stylesheet" media="screen" href="extensions/navigation/deck.navigation.css">
+ <link rel="stylesheet" media="screen" href="extensions/status/deck.status.css">
+ <link rel="stylesheet" media="screen" href="extensions/scale/deck.scale.css">
+
+ <!-- Style theme. More available in /themes/style/ or create your own. -->
+ <link rel="stylesheet" media="screen" href="themes/style/web-2.0.css">
+
+ <!-- Transition theme. More available in /themes/transition/ or create your own. -->
+ <link rel="stylesheet" media="screen" href="themes/transition/horizontal-slide.css">
+
+ <!-- Basic black and white print styles -->
+ <link rel="stylesheet" media="print" href="core/print.css">
+
+ <!-- Required Modernizr file -->
+ <script src="modernizr.custom.js"></script>
+</head>
+<body>
+ <div class="deck-container">
+
+ <!-- Begin slides. Just make elements with a class of slide. -->
+
+ <section class="slide">
+ <h1>Slide</h1>
+ </section>
+
+ <section class="slide">
+ <h1>Content</h1>
+ </section>
+
+ <section class="slide">
+ <h1>Here</h1>
+ </section>
+
+ <!-- End slides. -->
+
+ <!-- Begin extension snippets. Add or remove as needed. -->
+
+ <!-- deck.navigation snippet -->
+ <div aria-role="navigation">
+ <a href="#" class="deck-prev-link" title="Previous">&#8592;</a>
+ <a href="#" class="deck-next-link" title="Next">&#8594;</a>
+ </div>
+
+ <!-- deck.status snippet -->
+ <p class="deck-status" aria-role="status">
+ <span class="deck-status-current"></span>
+ /
+ <span class="deck-status-total"></span>
+ </p>
+
+ <!-- deck.goto snippet -->
+ <form action="." method="get" class="goto-form">
+ <label for="goto-slide">Go to slide:</label>
+ <input type="text" name="slidenum" id="goto-slide" list="goto-datalist">
+ <datalist id="goto-datalist"></datalist>
+ <input type="submit" value="Go">
+ </form>
+
+ <!-- End extension snippets. -->
+ </div>
+
+<!-- Required JS files. -->
+<script src="jquery.min.js"></script>
+<script src="core/deck.core.js"></script>
+
+<!-- Extension JS files. Add or remove as needed. -->
+<script src="extensions/menu/deck.menu.js"></script>
+<script src="extensions/goto/deck.goto.js"></script>
+<script src="extensions/status/deck.status.js"></script>
+<script src="extensions/navigation/deck.navigation.js"></script>
+<script src="extensions/scale/deck.scale.js"></script>
+
+<!-- Initialize the deck. You can put this in an external file if desired. -->
+<script>
+ $(function() {
+ $.deck('.slide');
+ });
+</script>
+</body>
+</html>
diff --git a/doc/backends/deckjs/deck.js/core/deck.core.css b/doc/backends/deckjs/deck.js/core/deck.core.css
new file mode 100644
index 00000000..da619cb0
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/core/deck.core.css
@@ -0,0 +1,60 @@
+html, body {
+ height: 100%;
+ padding: 0;
+ margin: 0;
+}
+
+.deck-container {
+ position: relative;
+ min-height: 100%;
+ margin: 0 auto;
+ overflow: hidden;
+ overflow-y: auto;
+}
+.js .deck-container {
+ visibility: hidden;
+}
+.ready .deck-container {
+ visibility: visible;
+}
+.touch .deck-container {
+ -webkit-text-size-adjust: none;
+ -moz-text-size-adjust: none;
+}
+
+.deck-loading {
+ display: none;
+}
+
+.slide {
+ width: auto;
+ min-height: 100%;
+ position: relative;
+}
+
+.deck-before, .deck-previous, .deck-next, .deck-after {
+ position: absolute;
+ left: -999em;
+ top: -999em;
+}
+
+.deck-current {
+ z-index: 2;
+}
+
+.slide .slide {
+ visibility: hidden;
+ position: static;
+ min-height: 0;
+}
+
+.deck-child-current {
+ position: static;
+ z-index: 2;
+}
+.deck-child-current .slide {
+ visibility: hidden;
+}
+.deck-child-current .deck-previous, .deck-child-current .deck-before, .deck-child-current .deck-current {
+ visibility: visible;
+}
diff --git a/doc/backends/deckjs/deck.js/core/deck.core.js b/doc/backends/deckjs/deck.js/core/deck.core.js
new file mode 100644
index 00000000..a8adefe7
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/core/deck.core.js
@@ -0,0 +1,748 @@
+/*!
+Deck JS - deck.core
+Copyright (c) 2011-2014 Caleb Troughton
+Dual licensed under the MIT license.
+https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt
+*/
+
+/*
+The deck.core module provides all the basic functionality for creating and
+moving through a deck. It does so by applying classes to indicate the state of
+the deck and its slides, allowing CSS to take care of the visual representation
+of each state. It also provides methods for navigating the deck and inspecting
+its state, as well as basic key bindings for going to the next and previous
+slides. More functionality is provided by wholly separate extension modules
+that use the API provided by core.
+*/
+(function($, undefined) {
+ var slides, currentIndex, $container, $fragmentLinks;
+
+ var events = {
+ /*
+ This event fires at the beginning of a slide change, before the actual
+ change occurs. Its purpose is to give extension authors a way to prevent
+ the slide change from occuring. This is done by calling preventDefault
+ on the event object within this event. If that is done, the deck.change
+ event will never be fired and the slide will not change.
+ */
+ beforeChange: 'deck.beforeChange',
+
+ /*
+ This event fires whenever the current slide changes, whether by way of
+ next, prev, or go. The callback function is passed two parameters, from
+ and to, equal to the indices of the old slide and the new slide
+ respectively. If preventDefault is called on the event within this handler
+ the slide change does not occur.
+
+ $(document).bind('deck.change', function(event, from, to) {
+ alert('Moving from slide ' + from + ' to ' + to);
+ });
+ */
+ change: 'deck.change',
+
+ /*
+ This event fires at the beginning of deck initialization. This event makes
+ a good hook for preprocessing extensions looking to modify the DOM before
+ the deck is fully initialized. It is also possible to halt the deck.init
+ event from firing while you do things in beforeInit. This can be done by
+ calling lockInit on the event object passed to this event. The init can be
+ released by calling releaseInit.
+
+ $(document).bind('deck.beforeInit', function(event) {
+ event.lockInit(); // halts deck.init event
+ window.setTimeout(function() {
+ event.releaseInit(); // deck.init will now fire 2 seconds later
+ }, 2000);
+ });
+
+ The init event will be fired regardless of locks after
+ options.initLockTimeout milliseconds.
+ */
+ beforeInitialize: 'deck.beforeInit',
+
+ /*
+ This event fires at the end of deck initialization. Extensions should
+ implement any code that relies on user extensible options (key bindings,
+ element selectors, classes) within a handler for this event. Native
+ events associated with Deck JS should be scoped under a .deck event
+ namespace, as with the example below:
+
+ var $d = $(document);
+ $.deck.defaults.keys.myExtensionKeycode = 70; // 'h'
+ $d.bind('deck.init', function() {
+ $d.bind('keydown.deck', function(event) {
+ if (event.which === $.deck.getOptions().keys.myExtensionKeycode) {
+ // Rock out
+ }
+ });
+ });
+ */
+ initialize: 'deck.init'
+ };
+
+ var options = {};
+ var $document = $(document);
+ var $window = $(window);
+ var stopPropagation = function(event) {
+ event.stopPropagation();
+ };
+
+ var updateContainerState = function() {
+ var oldIndex = $container.data('onSlide');
+ $container.removeClass(options.classes.onPrefix + oldIndex);
+ $container.addClass(options.classes.onPrefix + currentIndex);
+ $container.data('onSlide', currentIndex);
+ };
+
+ var updateChildCurrent = function() {
+ var $oldCurrent = $('.' + options.classes.current);
+ var $oldParents = $oldCurrent.parentsUntil(options.selectors.container);
+ var $newCurrent = slides[currentIndex];
+ var $newParents = $newCurrent.parentsUntil(options.selectors.container);
+ $oldParents.removeClass(options.classes.childCurrent);
+ $newParents.addClass(options.classes.childCurrent);
+ };
+
+ var removeOldSlideStates = function() {
+ var $all = $();
+ $.each(slides, function(i, el) {
+ $all = $all.add(el);
+ });
+ $all.removeClass([
+ options.classes.before,
+ options.classes.previous,
+ options.classes.current,
+ options.classes.next,
+ options.classes.after
+ ].join(' '));
+ };
+
+ var addNewSlideStates = function() {
+ slides[currentIndex].addClass(options.classes.current);
+ if (currentIndex > 0) {
+ slides[currentIndex-1].addClass(options.classes.previous);
+ }
+ if (currentIndex + 1 < slides.length) {
+ slides[currentIndex+1].addClass(options.classes.next);
+ }
+ if (currentIndex > 1) {
+ $.each(slides.slice(0, currentIndex - 1), function(i, $slide) {
+ $slide.addClass(options.classes.before);
+ });
+ }
+ if (currentIndex + 2 < slides.length) {
+ $.each(slides.slice(currentIndex+2), function(i, $slide) {
+ $slide.addClass(options.classes.after);
+ });
+ }
+ };
+
+ var setAriaHiddens = function() {
+ $(options.selectors.slides).each(function() {
+ var $slide = $(this);
+ var isSub = $slide.closest('.' + options.classes.childCurrent).length;
+ var isBefore = $slide.hasClass(options.classes.before) && !isSub;
+ var isPrevious = $slide.hasClass(options.classes.previous) && !isSub;
+ var isNext = $slide.hasClass(options.classes.next);
+ var isAfter = $slide.hasClass(options.classes.after);
+ var ariaHiddenValue = isBefore || isPrevious || isNext || isAfter;
+ $slide.attr('aria-hidden', ariaHiddenValue);
+ });
+ };
+
+ var updateStates = function() {
+ updateContainerState();
+ updateChildCurrent();
+ removeOldSlideStates();
+ addNewSlideStates();
+ if (options.setAriaHiddens) {
+ setAriaHiddens();
+ }
+ };
+
+ var initSlidesArray = function(elements) {
+ if ($.isArray(elements)) {
+ $.each(elements, function(i, element) {
+ slides.push($(element));
+ });
+ }
+ else {
+ $(elements).each(function(i, element) {
+ slides.push($(element));
+ });
+ }
+ };
+
+ var bindKeyEvents = function() {
+ var editables = [
+ 'input',
+ 'textarea',
+ 'select',
+ 'button',
+ 'meter',
+ 'progress',
+ '[contentEditable]'
+ ].join(', ');
+
+ $document.unbind('keydown.deck').bind('keydown.deck', function(event) {
+ var isNext = event.which === options.keys.next;
+ var isPrev = event.which === options.keys.previous;
+ isNext = isNext || $.inArray(event.which, options.keys.next) > -1;
+ isPrev = isPrev || $.inArray(event.which, options.keys.previous) > -1;
+
+ if (isNext) {
+ methods.next();
+ event.preventDefault();
+ }
+ else if (isPrev) {
+ methods.prev();
+ event.preventDefault();
+ }
+ });
+
+ $document.undelegate(editables, 'keydown.deck', stopPropagation);
+ $document.delegate(editables, 'keydown.deck', stopPropagation);
+ };
+
+ var bindTouchEvents = function() {
+ var startTouch;
+ var direction = options.touch.swipeDirection;
+ var tolerance = options.touch.swipeTolerance;
+ var listenToHorizontal = ({ both: true, horizontal: true })[direction];
+ var listenToVertical = ({ both: true, vertical: true })[direction];
+
+ $container.unbind('touchstart.deck');
+ $container.bind('touchstart.deck', function(event) {
+ if (!startTouch) {
+ startTouch = $.extend({}, event.originalEvent.targetTouches[0]);
+ }
+ });
+
+ $container.unbind('touchmove.deck');
+ $container.bind('touchmove.deck', function(event) {
+ $.each(event.originalEvent.changedTouches, function(i, touch) {
+ if (!startTouch || touch.identifier !== startTouch.identifier) {
+ return true;
+ }
+ var xDistance = touch.screenX - startTouch.screenX;
+ var yDistance = touch.screenY - startTouch.screenY;
+ var leftToRight = xDistance > tolerance && listenToHorizontal;
+ var rightToLeft = xDistance < -tolerance && listenToHorizontal;
+ var topToBottom = yDistance > tolerance && listenToVertical;
+ var bottomToTop = yDistance < -tolerance && listenToVertical;
+
+ if (leftToRight || topToBottom) {
+ $.deck('prev');
+ startTouch = undefined;
+ }
+ else if (rightToLeft || bottomToTop) {
+ $.deck('next');
+ startTouch = undefined;
+ }
+ return false;
+ });
+
+ if (listenToVertical) {
+ event.preventDefault();
+ }
+ });
+
+ $container.unbind('touchend.deck');
+ $container.bind('touchend.deck', function(event) {
+ $.each(event.originalEvent.changedTouches, function(i, touch) {
+ if (startTouch && touch.identifier === startTouch.identifier) {
+ startTouch = undefined;
+ }
+ });
+ });
+ };
+
+ var indexInBounds = function(index) {
+ return typeof index === 'number' && index >=0 && index < slides.length;
+ };
+
+ var createBeforeInitEvent = function() {
+ var event = $.Event(events.beforeInitialize);
+ event.locks = 0;
+ event.done = $.noop;
+ event.lockInit = function() {
+ ++event.locks;
+ };
+ event.releaseInit = function() {
+ --event.locks;
+ if (!event.locks) {
+ event.done();
+ }
+ };
+ return event;
+ };
+
+ var goByHash = function(str) {
+ var id = str.substr(str.indexOf("#") + 1);
+
+ $.each(slides, function(i, $slide) {
+ if ($slide.attr('id') === id) {
+ $.deck('go', i);
+ return false;
+ }
+ });
+
+ // If we don't set these to 0 the container scrolls due to hashchange
+ if (options.preventFragmentScroll) {
+ $.deck('getContainer').scrollLeft(0).scrollTop(0);
+ }
+ };
+
+ var assignSlideId = function(i, $slide) {
+ var currentId = $slide.attr('id');
+ var previouslyAssigned = $slide.data('deckAssignedId') === currentId;
+ if (!currentId || previouslyAssigned) {
+ $slide.attr('id', options.hashPrefix + i);
+ $slide.data('deckAssignedId', options.hashPrefix + i);
+ }
+ };
+
+ var removeContainerHashClass = function(id) {
+ $container.removeClass(options.classes.onPrefix + id);
+ };
+
+ var addContainerHashClass = function(id) {
+ $container.addClass(options.classes.onPrefix + id);
+ };
+
+ var setupHashBehaviors = function() {
+ $fragmentLinks = $();
+ $.each(slides, function(i, $slide) {
+ var hash;
+
+ assignSlideId(i, $slide);
+ hash = '#' + $slide.attr('id');
+ if (hash === window.location.hash) {
+ setTimeout(function() {
+ $.deck('go', i);
+ }, 1);
+ }
+ $fragmentLinks = $fragmentLinks.add('a[href="' + hash + '"]');
+ });
+
+ if (slides.length) {
+ addContainerHashClass($.deck('getSlide').attr('id'));
+ };
+ };
+
+ var changeHash = function(from, to) {
+ var hash = '#' + $.deck('getSlide', to).attr('id');
+ var hashPath = window.location.href.replace(/#.*/, '') + hash;
+
+ removeContainerHashClass($.deck('getSlide', from).attr('id'));
+ addContainerHashClass($.deck('getSlide', to).attr('id'));
+ if (Modernizr.history) {
+ window.history.replaceState({}, "", hashPath);
+ }
+ };
+
+ /* Methods exposed in the jQuery.deck namespace */
+ var methods = {
+
+ /*
+ jQuery.deck(selector, options)
+
+ selector: string | jQuery | array
+ options: object, optional
+
+ Initializes the deck, using each element matched by selector as a slide.
+ May also be passed an array of string selectors or jQuery objects, in
+ which case each selector in the array is considered a slide. The second
+ parameter is an optional options object which will extend the default
+ values.
+
+ Users may also pass only an options object to init. In this case the slide
+ selector will be options.selectors.slides which defaults to .slide.
+
+ $.deck('.slide');
+
+ or
+
+ $.deck([
+ '#first-slide',
+ '#second-slide',
+ '#etc'
+ ]);
+ */
+ init: function(opts) {
+ var beforeInitEvent = createBeforeInitEvent();
+ var overrides = opts;
+
+ if (!$.isPlainObject(opts)) {
+ overrides = arguments[1] || {};
+ $.extend(true, overrides, {
+ selectors: {
+ slides: arguments[0]
+ }
+ });
+ }
+
+ options = $.extend(true, {}, $.deck.defaults, overrides);
+ slides = [];
+ currentIndex = 0;
+ $container = $(options.selectors.container);
+
+ // Hide the deck while states are being applied to kill transitions
+ $container.addClass(options.classes.loading);
+
+ // populate the array of slides for pre-init
+ initSlidesArray(options.selectors.slides);
+ // Pre init event for preprocessing hooks
+ beforeInitEvent.done = function() {
+ // re-populate the array of slides
+ slides = [];
+ initSlidesArray(options.selectors.slides);
+ setupHashBehaviors();
+ bindKeyEvents();
+ bindTouchEvents();
+ $container.scrollLeft(0).scrollTop(0);
+
+ if (slides.length) {
+ updateStates();
+ }
+
+ // Show deck again now that slides are in place
+ $container.removeClass(options.classes.loading);
+ $document.trigger(events.initialize);
+ };
+
+ $document.trigger(beforeInitEvent);
+ if (!beforeInitEvent.locks) {
+ beforeInitEvent.done();
+ }
+ window.setTimeout(function() {
+ if (beforeInitEvent.locks) {
+ if (window.console) {
+ window.console.warn('Something locked deck initialization\
+ without releasing it before the timeout. Proceeding with\
+ initialization anyway.');
+ }
+ beforeInitEvent.done();
+ }
+ }, options.initLockTimeout);
+ },
+
+ /*
+ jQuery.deck('go', index)
+
+ index: integer | string
+
+ Moves to the slide at the specified index if index is a number. Index is
+ 0-based, so $.deck('go', 0); will move to the first slide. If index is a
+ string this will move to the slide with the specified id. If index is out
+ of bounds or doesn't match a slide id the call is ignored.
+ */
+ go: function(indexOrId) {
+ var beforeChangeEvent = $.Event(events.beforeChange);
+ var index;
+
+ /* Number index, easy. */
+ if (indexInBounds(indexOrId)) {
+ index = indexOrId;
+ }
+ /* Id string index, search for it and set integer index */
+ else if (typeof indexOrId === 'string') {
+ $.each(slides, function(i, $slide) {
+ if ($slide.attr('id') === indexOrId) {
+ index = i;
+ return false;
+ }
+ });
+ }
+ if (typeof index === 'undefined') {
+ return;
+ }
+
+ /* Trigger beforeChange. If nothing prevents the change, trigger
+ the slide change. */
+ $document.trigger(beforeChangeEvent, [currentIndex, index]);
+ if (!beforeChangeEvent.isDefaultPrevented()) {
+ $document.trigger(events.change, [currentIndex, index]);
+ changeHash(currentIndex, index);
+ currentIndex = index;
+ updateStates();
+ }
+ },
+
+ /*
+ jQuery.deck('next')
+
+ Moves to the next slide. If the last slide is already active, the call
+ is ignored.
+ */
+ next: function() {
+ methods.go(currentIndex+1);
+ },
+
+ /*
+ jQuery.deck('prev')
+
+ Moves to the previous slide. If the first slide is already active, the
+ call is ignored.
+ */
+ prev: function() {
+ methods.go(currentIndex-1);
+ },
+
+ /*
+ jQuery.deck('getSlide', index)
+
+ index: integer, optional
+
+ Returns a jQuery object containing the slide at index. If index is not
+ specified, the current slide is returned.
+ */
+ getSlide: function(index) {
+ index = typeof index !== 'undefined' ? index : currentIndex;
+ if (!indexInBounds(index)) {
+ return null;
+ }
+ return slides[index];
+ },
+
+ /*
+ jQuery.deck('getSlides')
+
+ Returns all slides as an array of jQuery objects.
+ */
+ getSlides: function() {
+ return slides;
+ },
+
+ /*
+ jQuery.deck('getTopLevelSlides')
+
+ Returns all slides that are not subslides.
+ */
+ getTopLevelSlides: function() {
+ var topLevelSlides = [];
+ var slideSelector = options.selectors.slides;
+ var subSelector = [slideSelector, slideSelector].join(' ');
+ $.each(slides, function(i, $slide) {
+ if (!$slide.is(subSelector)) {
+ topLevelSlides.push($slide);
+ }
+ });
+ return topLevelSlides;
+ },
+
+ /*
+ jQuery.deck('getNestedSlides', index)
+
+ index: integer, optional
+
+ Returns all the nested slides of the current slide. If index is
+ specified it returns the nested slides of the slide at that index.
+ If there are no nested slides this will return an empty array.
+ */
+ getNestedSlides: function(index) {
+ var targetIndex = index == null ? currentIndex : index;
+ var $targetSlide = $.deck('getSlide', targetIndex);
+ var $nesteds = $targetSlide.find(options.selectors.slides);
+ var nesteds = $nesteds.get();
+ return $.map(nesteds, function(slide, i) {
+ return $(slide);
+ });
+ },
+
+
+ /*
+ jQuery.deck('getContainer')
+
+ Returns a jQuery object containing the deck container as defined by the
+ container option.
+ */
+ getContainer: function() {
+ return $container;
+ },
+
+ /*
+ jQuery.deck('getOptions')
+
+ Returns the options object for the deck, including any overrides that
+ were defined at initialization.
+ */
+ getOptions: function() {
+ return options;
+ },
+
+ /*
+ jQuery.deck('extend', name, method)
+
+ name: string
+ method: function
+
+ Adds method to the deck namespace with the key of name. This doesn’t
+ give access to any private member data — public methods must still be
+ used within method — but lets extension authors piggyback on the deck
+ namespace rather than pollute jQuery.
+
+ $.deck('extend', 'alert', function(msg) {
+ alert(msg);
+ });
+
+ // Alerts 'boom'
+ $.deck('alert', 'boom');
+ */
+ extend: function(name, method) {
+ methods[name] = method;
+ }
+ };
+
+ /* jQuery extension */
+ $.deck = function(method, arg) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (methods[method]) {
+ return methods[method].apply(this, args);
+ }
+ else {
+ return methods.init(method, arg);
+ }
+ };
+
+ /*
+ The default settings object for a deck. All deck extensions should extend
+ this object to add defaults for any of their options.
+
+ options.classes.after
+ This class is added to all slides that appear after the 'next' slide.
+
+ options.classes.before
+ This class is added to all slides that appear before the 'previous'
+ slide.
+
+ options.classes.childCurrent
+ This class is added to all elements in the DOM tree between the
+ 'current' slide and the deck container. For standard slides, this is
+ mostly seen and used for nested slides.
+
+ options.classes.current
+ This class is added to the current slide.
+
+ options.classes.loading
+ This class is applied to the deck container during loading phases and is
+ primarily used as a way to short circuit transitions between states
+ where such transitions are distracting or unwanted. For example, this
+ class is applied during deck initialization and then removed to prevent
+ all the slides from appearing stacked and transitioning into place
+ on load.
+
+ options.classes.next
+ This class is added to the slide immediately following the 'current'
+ slide.
+
+ options.classes.onPrefix
+ This prefix, concatenated with the current slide index, is added to the
+ deck container as you change slides.
+
+ options.classes.previous
+ This class is added to the slide immediately preceding the 'current'
+ slide.
+
+ options.selectors.container
+ Elements matched by this CSS selector will be considered the deck
+ container. The deck container is used to scope certain states of the
+ deck, as with the onPrefix option, or with extensions such as deck.goto
+ and deck.menu.
+
+ options.selectors.slides
+ Elements matched by this selector make up the individual deck slides.
+ If a user chooses to pass the slide selector as the first argument to
+ $.deck() on initialization it does the same thing as passing in this
+ option and this option value will be set to the value of that parameter.
+
+ options.keys.next
+ The numeric keycode used to go to the next slide.
+
+ options.keys.previous
+ The numeric keycode used to go to the previous slide.
+
+ options.touch.swipeDirection
+ The direction swipes occur to cause slide changes. Can be 'horizontal',
+ 'vertical', or 'both'. Any other value or a falsy value will disable
+ swipe gestures for navigation.
+
+ options.touch.swipeTolerance
+ The number of pixels the users finger must travel to produce a swipe
+ gesture.
+
+ options.initLockTimeout
+ The number of milliseconds the init event will wait for BeforeInit event
+ locks to be released before firing the init event regardless.
+
+ options.hashPrefix
+ Every slide that does not have an id is assigned one at initialization.
+ Assigned ids take the form of hashPrefix + slideIndex, e.g., slide-0,
+ slide-12, etc.
+
+ options.preventFragmentScroll
+ When deep linking to a hash of a nested slide, this scrolls the deck
+ container to the top, undoing the natural browser behavior of scrolling
+ to the document fragment on load.
+
+ options.setAriaHiddens
+ When set to true, deck.js will set aria hidden attributes for slides
+ that do not appear onscreen according to a typical heirarchical
+ deck structure. You may want to turn this off if you are using a theme
+ where slides besides the current slide are visible on screen and should
+ be accessible to screenreaders.
+ */
+ $.deck.defaults = {
+ classes: {
+ after: 'deck-after',
+ before: 'deck-before',
+ childCurrent: 'deck-child-current',
+ current: 'deck-current',
+ loading: 'deck-loading',
+ next: 'deck-next',
+ onPrefix: 'on-slide-',
+ previous: 'deck-previous'
+ },
+
+ selectors: {
+ container: '.deck-container',
+ slides: '.slide'
+ },
+
+ keys: {
+ // enter, space, page down, right arrow, down arrow,
+ next: [13, 32, 34, 39, 40],
+ // backspace, page up, left arrow, up arrow
+ previous: [8, 33, 37, 38]
+ },
+
+ touch: {
+ swipeDirection: 'horizontal',
+ swipeTolerance: 60
+ },
+
+ initLockTimeout: 10000,
+ hashPrefix: 'slide-',
+ preventFragmentScroll: true,
+ setAriaHiddens: true
+ };
+
+ $document.ready(function() {
+ $('html').addClass('ready');
+ });
+
+ $window.bind('hashchange.deck', function(event) {
+ if (event.originalEvent && event.originalEvent.newURL) {
+ goByHash(event.originalEvent.newURL);
+ }
+ else {
+ goByHash(window.location.hash);
+ }
+ });
+
+ $window.bind('load.deck', function() {
+ if (options.preventFragmentScroll) {
+ $container.scrollLeft(0).scrollTop(0);
+ }
+ });
+})(jQuery);
diff --git a/doc/backends/deckjs/deck.js/core/deck.core.scss b/doc/backends/deckjs/deck.js/core/deck.core.scss
new file mode 100755
index 00000000..baab0fd9
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/core/deck.core.scss
@@ -0,0 +1,65 @@
+html, body {
+ height:100%;
+ padding:0;
+ margin:0;
+}
+
+.deck-container {
+ position:relative;
+ min-height:100%;
+ margin:0 auto;
+ overflow:hidden;
+ overflow-y:auto;
+
+ .js & {
+ visibility:hidden;
+ }
+
+ .ready & {
+ visibility:visible;
+ }
+
+ .touch & {
+ -webkit-text-size-adjust:none;
+ -moz-text-size-adjust:none;
+ }
+}
+
+.deck-loading {
+ display:none;
+}
+
+.slide {
+ width:auto;
+ min-height:100%;
+ position:relative;
+}
+
+.deck-before, .deck-previous, .deck-next, .deck-after {
+ position:absolute;
+ left:-999em;
+ top:-999em;
+}
+
+.deck-current {
+ z-index:2;
+}
+
+.slide .slide {
+ visibility:hidden;
+ position:static;
+ min-height:0;
+}
+
+.deck-child-current {
+ position:static;
+ z-index:2;
+
+ .slide {
+ visibility:hidden;
+ }
+
+ .deck-previous, .deck-before, .deck-current {
+ visibility:visible;
+ }
+} \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/core/print.css b/doc/backends/deckjs/deck.js/core/print.css
new file mode 100644
index 00000000..0230f4c1
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/core/print.css
@@ -0,0 +1,25 @@
+body {
+ font-size: 18pt;
+}
+
+h1 {
+ font-size: 48pt;
+}
+
+h2 {
+ font-size: 36pt;
+}
+
+h3 {
+ font-size: 28pt;
+}
+
+pre {
+ border: 1px solid #000;
+ padding: 10px;
+ white-space: pre-wrap;
+}
+
+.deck-container > .slide {
+ page-break-after: always;
+}
diff --git a/doc/backends/deckjs/deck.js/core/print.scss b/doc/backends/deckjs/deck.js/core/print.scss
new file mode 100644
index 00000000..02acd4bf
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/core/print.scss
@@ -0,0 +1,14 @@
+body { font-size:18pt; }
+h1 { font-size:48pt; }
+h2 { font-size:36pt; }
+h3 { font-size:28pt; }
+
+pre {
+ border:1px solid #000;
+ padding:10px;
+ white-space:pre-wrap;
+}
+
+.deck-container > .slide {
+ page-break-after: always;
+}
diff --git a/doc/backends/deckjs/deck.js/extensions/deck.js-blank/README.md b/doc/backends/deckjs/deck.js/extensions/deck.js-blank/README.md
new file mode 100644
index 00000000..0d5c882a
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/deck.js-blank/README.md
@@ -0,0 +1,10 @@
+#deck.blank.js
+
+Deck.blank.js is an extension for the deck.js framework to allow blanking of the current slide, to draw the attention back to the presenter
+
+At the moment, the key 'b' is hardcoded to blank/unblank.
+
+##Todo
+
+- make the blanking key configurable
+- make the background-color during blanking configurable \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/extensions/deck.js-blank/deck.blank.js b/doc/backends/deckjs/deck.js/extensions/deck.js-blank/deck.blank.js
new file mode 100644
index 00000000..01955834
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/deck.js-blank/deck.blank.js
@@ -0,0 +1,33 @@
+/*!
+Deck JS - deck.blank - v1.0
+Copyright (c) 2012 Mike Kellenberger
+*/
+
+/*
+This module adds the necessary methods and key bindings to blank/unblank the screen by pressing 'b'.
+*/
+(function($, deck, undefined) {
+ var $d = $(document);
+
+ $[deck]('extend', 'activateBlankScreen', function() {
+ $[deck]('getSlide').hide();
+ });
+
+ $[deck]('extend', 'deactivateBlankScreen', function() {
+ $[deck]('getSlide').show();
+ });
+
+ $[deck]('extend', 'blankScreen', function() {
+ $[deck]('getSlide').is(":visible") ? $[deck]('activateBlankScreen') : $[deck]('deactivateBlankScreen');
+ });
+
+ $d.bind('deck.init', function() {
+ // Bind key events
+ $d.unbind('keydown.blank').bind('keydown.blank', function(e) {
+ if (e.which==66) {
+ $[deck]('blankScreen');
+ e.preventDefault();
+ }
+ });
+ });
+})(jQuery, 'deck'); \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/extensions/goto/deck.goto.css b/doc/backends/deckjs/deck.js/extensions/goto/deck.goto.css
new file mode 100644
index 00000000..935574a1
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/goto/deck.goto.css
@@ -0,0 +1,36 @@
+.goto-form {
+ position: absolute;
+ z-index: 3;
+ bottom: 10px;
+ left: 50%;
+ height: 1.75em;
+ margin: 0 0 0 -9.125em;
+ line-height: 1.75em;
+ padding: 0.625em;
+ display: none;
+ background: #ccc;
+ overflow: hidden;
+ border-radius: 10px;
+}
+.goto-form label {
+ font-weight: bold;
+}
+.goto-form label, .goto-form input {
+ display: inline-block;
+ font-family: inherit;
+}
+.deck-goto .goto-form {
+ display: block;
+}
+
+#goto-slide {
+ width: 8.375em;
+ margin: 0 0.625em;
+ height: 1.4375em;
+}
+
+@media print {
+ .goto-form, #goto-slide {
+ display: none;
+ }
+}
diff --git a/doc/backends/deckjs/deck.js/extensions/goto/deck.goto.html b/doc/backends/deckjs/deck.js/extensions/goto/deck.goto.html
new file mode 100644
index 00000000..4b739982
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/goto/deck.goto.html
@@ -0,0 +1,7 @@
+<!-- Place the following snippet at the bottom of the deck container. -->
+<form action="." method="get" class="goto-form">
+ <label for="goto-slide">Go to slide:</label>
+ <input type="text" name="slidenum" id="goto-slide" list="goto-datalist">
+ <datalist id="goto-datalist"></datalist>
+ <input type="submit" value="Go">
+</form> \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/extensions/goto/deck.goto.js b/doc/backends/deckjs/deck.js/extensions/goto/deck.goto.js
new file mode 100644
index 00000000..6a90f16c
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/goto/deck.goto.js
@@ -0,0 +1,190 @@
+/*!
+Deck JS - deck.goto
+Copyright (c) 2011-2014 Caleb Troughton
+Dual licensed under the MIT license.
+https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt
+*/
+
+/*
+This module adds the necessary methods and key bindings to show and hide a form
+for jumping to any slide number/id in the deck (and processes that form
+accordingly). The form-showing state is indicated by the presence of a class on
+the deck container.
+*/
+(function($, undefined) {
+ var $document = $(document);
+ var rootCounter;
+
+ var bindKeyEvents = function() {
+ $document.unbind('keydown.deckgoto');
+ $document.bind('keydown.deckgoto', function(event) {
+ var key = $.deck('getOptions').keys.goto;
+ if (event.which === key || $.inArray(event.which, key) > -1) {
+ event.preventDefault();
+ $.deck('toggleGoTo');
+ }
+ });
+ };
+
+ var populateDatalist = function() {
+ var options = $.deck('getOptions');
+ var $datalist = $(options.selectors.gotoDatalist);
+
+ $.each($.deck('getSlides'), function(i, $slide) {
+ var id = $slide.attr('id');
+ if (id) {
+ $datalist.append('<option value="' + id + '">');
+ }
+ });
+ };
+
+ var markRootSlides = function() {
+ var options = $.deck('getOptions');
+ var slideTest = $.map([
+ options.classes.before,
+ options.classes.previous,
+ options.classes.current,
+ options.classes.next,
+ options.classes.after
+ ], function(el, i) {
+ return '.' + el;
+ }).join(', ');
+
+ rootCounter = 0;
+ $.each($.deck('getSlides'), function(i, $slide) {
+ var $parentSlides = $slide.parentsUntil(
+ options.selectors.container,
+ slideTest
+ );
+
+ if ($parentSlides.length) {
+ $slide.removeData('rootIndex');
+ }
+ else if (!options.countNested) {
+ ++rootCounter;
+ $slide.data('rootIndex', rootCounter);
+ }
+ });
+ };
+
+ var handleFormSubmit = function() {
+ var options = $.deck('getOptions');
+ var $form = $(options.selectors.gotoForm);
+
+ $form.unbind('submit.deckgoto');
+ $form.bind('submit.deckgoto', function(event) {
+ var $field = $(options.selectors.gotoInput);
+ var indexOrId = $field.val();
+ var index = parseInt(indexOrId, 10);
+
+ if (!options.countNested) {
+ if (!isNaN(index) && index >= rootCounter) {
+ return false;
+ }
+ $.each($.deck('getSlides'), function(i, $slide) {
+ if ($slide.data('rootIndex') === index) {
+ index = i + 1;
+ return false;
+ }
+ });
+ }
+
+ $.deck('go', isNaN(index) ? indexOrId : index - 1);
+ $.deck('hideGoTo');
+ $field.val('');
+ event.preventDefault();
+ });
+ };
+
+ /*
+ Extends defaults/options.
+
+ options.classes.goto
+ This class is added to the deck container when showing the Go To Slide
+ form.
+
+ options.selectors.gotoDatalist
+ The element that matches this selector is the datalist element that will
+ be populated with options for each of the slide ids. In browsers that
+ support the datalist element, this provides a drop list of slide ids to
+ aid the user in selecting a slide.
+
+ options.selectors.gotoForm
+ The element that matches this selector is the form that is submitted
+ when a user hits enter after typing a slide number/id in the gotoInput
+ element.
+
+ options.selectors.gotoInput
+ The element that matches this selector is the text input field for
+ entering a slide number/id in the Go To Slide form.
+
+ options.keys.goto
+ The numeric keycode used to show the Go To Slide form.
+
+ options.countNested
+ If false, only top level slides will be counted when entering a
+ slide number.
+ */
+ $.extend(true, $.deck.defaults, {
+ classes: {
+ goto: 'deck-goto'
+ },
+
+ selectors: {
+ gotoDatalist: '#goto-datalist',
+ gotoForm: '.goto-form',
+ gotoInput: '#goto-slide'
+ },
+
+ keys: {
+ goto: 71 // g
+ },
+
+ countNested: true
+ });
+
+ /*
+ jQuery.deck('showGoTo')
+
+ Shows the Go To Slide form by adding the class specified by the goto class
+ option to the deck container.
+ */
+ $.deck('extend', 'showGoTo', function() {
+ var options = $.deck('getOptions');
+ $.deck('getContainer').addClass(options.classes.goto);
+ $(options.selectors.gotoForm).attr('aria-hidden', false);
+ $(options.selectors.gotoInput).focus();
+ });
+
+ /*
+ jQuery.deck('hideGoTo')
+
+ Hides the Go To Slide form by removing the class specified by the goto class
+ option from the deck container.
+ */
+ $.deck('extend', 'hideGoTo', function() {
+ var options = $.deck('getOptions');
+ $(options.selectors.gotoInput).blur();
+ $.deck('getContainer').removeClass(options.classes.goto);
+ $(options.selectors.gotoForm).attr('aria-hidden', true);
+ });
+
+ /*
+ jQuery.deck('toggleGoTo')
+
+ Toggles between showing and hiding the Go To Slide form.
+ */
+ $.deck('extend', 'toggleGoTo', function() {
+ var options = $.deck('getOptions');
+ var hasGotoClass = $.deck('getContainer').hasClass(options.classes.goto);
+ $.deck(hasGotoClass ? 'hideGoTo' : 'showGoTo');
+ });
+
+ $document.bind('deck.init', function() {
+ bindKeyEvents();
+ populateDatalist();
+ markRootSlides();
+ handleFormSubmit();
+ });
+})(jQuery);
+
diff --git a/doc/backends/deckjs/deck.js/extensions/goto/deck.goto.scss b/doc/backends/deckjs/deck.js/extensions/goto/deck.goto.scss
new file mode 100755
index 00000000..667219fa
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/goto/deck.goto.scss
@@ -0,0 +1,39 @@
+.goto-form {
+ position:absolute;
+ z-index:3;
+ bottom:10px;
+ left:50%;
+ height:1.75em;
+ margin:0 0 0 -9.125em;
+ line-height:1.75em;
+ padding:0.625em;
+ display:none;
+ background:#ccc;
+ overflow:hidden;
+ border-radius:10px;
+
+ label {
+ font-weight:bold;
+ }
+
+ label, input {
+ display:inline-block;
+ font-family:inherit;
+ }
+
+ .deck-goto & {
+ display:block;
+ }
+}
+
+#goto-slide {
+ width:8.375em;
+ margin:0 0.625em;
+ height:1.4375em;
+}
+
+@media print {
+ .goto-form, #goto-slide {
+ display:none;
+ }
+} \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/extensions/menu/deck.menu.css b/doc/backends/deckjs/deck.js/extensions/menu/deck.menu.css
new file mode 100644
index 00000000..a0f4e007
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/menu/deck.menu.css
@@ -0,0 +1,45 @@
+.deck-menu {
+ overflow: auto;
+}
+.deck-menu .slide {
+ background: #eee;
+ position: relative;
+ left: 0;
+ top: 0;
+ visibility: visible;
+ cursor: pointer;
+}
+.no-csstransforms .deck-menu > .slide {
+ float: left;
+ width: 22%;
+ height: 22%;
+ min-height: 0;
+ margin: 1%;
+ font-size: 0.22em;
+ overflow: hidden;
+ padding: 0 0.5%;
+}
+.csstransforms .deck-menu > .slide {
+ -webkit-transform: scale(0.22) !important;
+ -ms-transform: scale(0.22) !important;
+ transform: scale(0.22) !important;
+ -webkit-transform-origin: 0 0;
+ -ms-transform-origin: 0 0;
+ transform-origin: 0 0;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ padding: 0 48px;
+ margin: 12px;
+}
+.deck-menu iframe, .deck-menu img, .deck-menu video {
+ max-width: 100%;
+}
+.deck-menu .deck-current, .no-touch .deck-menu .slide:hover {
+ background: #ddf;
+}
+.deck-menu.deck-container:hover .deck-prev-link, .deck-menu.deck-container:hover .deck-next-link {
+ display: none;
+}
diff --git a/doc/backends/deckjs/deck.js/extensions/menu/deck.menu.js b/doc/backends/deckjs/deck.js/extensions/menu/deck.menu.js
new file mode 100644
index 00000000..77cf8c55
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/menu/deck.menu.js
@@ -0,0 +1,225 @@
+/*!
+Deck JS - deck.menu
+Copyright (c) 2011-2014 Caleb Troughton
+Dual licensed under the MIT license.
+https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt
+*/
+
+/*
+This module adds the methods and key binding to show and hide a menu of all
+slides in the deck. The deck menu state is indicated by the presence of a class
+on the deck container.
+*/
+(function($, undefined) {
+ var $document = $(document);
+ var $html = $('html');
+ var rootSlides;
+
+ var populateRootSlidesArray = function() {
+ var options = $.deck('getOptions');
+ var slideTest = $.map([
+ options.classes.before,
+ options.classes.previous,
+ options.classes.current,
+ options.classes.next,
+ options.classes.after
+ ], function(el, i) {
+ return '.' + el;
+ }).join(', ');
+
+ rootSlides = [];
+ $.each($.deck('getSlides'), function(i, $slide) {
+ var $parentSlides = $slide.parentsUntil(
+ options.selectors.container,
+ slideTest
+ );
+ if (!$parentSlides.length) {
+ rootSlides.push($slide);
+ }
+ });
+ };
+
+ var bindKeyEvents = function() {
+ var options = $.deck('getOptions');
+ $document.unbind('keydown.deckmenu');
+ $document.bind('keydown.deckmenu', function(event) {
+ var isMenuKey = event.which === options.keys.menu;
+ isMenuKey = isMenuKey || $.inArray(event.which, options.keys.menu) > -1;
+ if (isMenuKey && !event.ctrlKey) {
+ $.deck('toggleMenu');
+ event.preventDefault();
+ }
+ });
+ };
+
+ var bindTouchEvents = function() {
+ var $container = $.deck('getContainer');
+ var options = $.deck('getOptions');
+ var touchEndTime = 0;
+ var currentSlide;
+
+ $container.unbind('touchstart.deckmenu');
+ $container.bind('touchstart.deckmenu', function() {
+ currentSlide = $.deck('getSlide');
+ });
+ $container.unbind('touchend.deckmenu');
+ $container.bind('touchend.deckmenu', function(event) {
+ var now = Date.now();
+ var isDoubletap = now - touchEndTime < options.touch.doubletapWindow;
+
+ // Ignore this touch event if it caused a nav change (swipe)
+ if (currentSlide !== $.deck('getSlide')) {
+ return;
+ }
+ if (isDoubletap) {
+ $.deck('toggleMenu');
+ event.preventDefault();
+ }
+ touchEndTime = now;
+ });
+ };
+
+ var setupMenuSlideSelection = function() {
+ var options = $.deck('getOptions');
+
+ $.each($.deck('getSlides'), function(i, $slide) {
+ $slide.unbind('click.deckmenu');
+ $slide.bind('click.deckmenu', function(event) {
+ if (!$.deck('getContainer').hasClass(options.classes.menu)) {
+ return;
+ }
+ $.deck('go', i);
+ $.deck('hideMenu');
+ event.stopPropagation();
+ event.preventDefault();
+ });
+ });
+ };
+
+ /*
+ Extends defaults/options.
+
+ options.classes.menu
+ This class is added to the deck container when showing the slide menu.
+
+ options.keys.menu
+ The numeric keycode used to toggle between showing and hiding the slide
+ menu.
+
+ options.touch.doubletapWindow
+ Two consecutive touch events within this number of milliseconds will
+ be considered a double tap, and will toggle the menu on touch devices.
+ */
+ $.extend(true, $.deck.defaults, {
+ classes: {
+ menu: 'deck-menu'
+ },
+
+ keys: {
+ menu: 77 // m
+ },
+
+ touch: {
+ doubletapWindow: 400
+ }
+ });
+
+ /*
+ jQuery.deck('showMenu')
+
+ Shows the slide menu by adding the class specified by the menu class option
+ to the deck container.
+ */
+ $.deck('extend', 'showMenu', function() {
+ var $container = $.deck('getContainer');
+ var options = $.deck('getOptions');
+
+ if ($container.hasClass(options.classes.menu)) {
+ return;
+ }
+
+ // Hide through loading class to short-circuit transitions (perf)
+ $container.addClass([
+ options.classes.loading,
+ options.classes.menu
+ ].join(' '));
+
+ /* Forced to do this in JS until CSS learns second-grade math. Save old
+ style value for restoration when menu is hidden. */
+ if (Modernizr.csstransforms) {
+ $.each(rootSlides, function(i, $slide) {
+ $slide.data('oldStyle', $slide.attr('style'));
+ $slide.css({
+ 'position': 'absolute',
+ 'left': ((i % 4) * 25) + '%',
+ 'top': (Math.floor(i / 4) * 25) + '%'
+ });
+ });
+ }
+
+ // Need to ensure the loading class renders first, then remove
+ window.setTimeout(function() {
+ $container.removeClass(options.classes.loading);
+ $container.scrollTop($.deck('getSlide').position().top);
+ }, 0);
+ });
+
+ /*
+ jQuery.deck('hideMenu')
+
+ Hides the slide menu by removing the class specified by the menu class
+ option from the deck container.
+ */
+ $.deck('extend', 'hideMenu', function() {
+ var $container = $.deck('getContainer');
+ var options = $.deck('getOptions');
+
+ if (!$container.hasClass(options.classes.menu)) {
+ return;
+ }
+
+ $container.removeClass(options.classes.menu);
+ $container.addClass(options.classes.loading);
+
+ /* Restore old style value */
+ if (Modernizr.csstransforms) {
+ $.each(rootSlides, function(i, $slide) {
+ var oldStyle = $slide.data('oldStyle');
+ $slide.attr('style', oldStyle ? oldStyle : '');
+ });
+ }
+
+ window.setTimeout(function() {
+ $container.removeClass(options.classes.loading);
+ $container.scrollTop(0);
+ }, 0);
+ });
+
+ /*
+ jQuery.deck('toggleMenu')
+
+ Toggles between showing and hiding the slide menu.
+ */
+ $.deck('extend', 'toggleMenu', function() {
+ $.deck('getContainer').hasClass($.deck('getOptions').classes.menu) ?
+ $.deck('hideMenu') : $.deck('showMenu');
+ });
+
+ $document.bind('deck.init', function() {
+ populateRootSlidesArray();
+ bindKeyEvents();
+ bindTouchEvents();
+ setupMenuSlideSelection();
+ });
+
+ $document.bind('deck.change', function(event, from, to) {
+ var $container = $.deck('getContainer');
+ var containerScroll, slideTop;
+
+ if ($container.hasClass($.deck('getOptions').classes.menu)) {
+ containerScroll = $container.scrollTop();
+ slideTop = $.deck('getSlide', to).position().top;
+ $container.scrollTop(containerScroll + slideTop);
+ }
+ });
+})(jQuery);
diff --git a/doc/backends/deckjs/deck.js/extensions/menu/deck.menu.scss b/doc/backends/deckjs/deck.js/extensions/menu/deck.menu.scss
new file mode 100755
index 00000000..2c6b3ae8
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/menu/deck.menu.scss
@@ -0,0 +1,55 @@
+.deck-menu {
+ overflow:auto;
+
+ .slide {
+ background:#eee;
+ position:relative;
+ left:0;
+ top:0;
+ visibility:visible;
+ cursor:pointer;
+ }
+
+ > .slide {
+ .no-csstransforms & {
+ float:left;
+ width:22%;
+ height:22%;
+ min-height:0;
+ margin:1%;
+ font-size:0.22em;
+ overflow:hidden;
+ padding:0 0.5%;
+ }
+
+ .csstransforms & {
+ -webkit-transform:scale(.22) !important;
+ -ms-transform:scale(.22) !important;
+ transform:scale(.22) !important;
+ -webkit-transform-origin:0 0;
+ -ms-transform-origin:0 0;
+ transform-origin:0 0;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width:100%;
+ height:100%;
+ overflow:hidden;
+ padding:0 48px;
+ margin:12px;
+ }
+ }
+
+ iframe, img, video {
+ max-width:100%;
+ }
+
+ .deck-current, .no-touch & .slide:hover {
+ background:#ddf;
+ }
+
+ &.deck-container:hover {
+ .deck-prev-link, .deck-next-link {
+ display:none;
+ }
+ }
+} \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.css b/doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.css
new file mode 100644
index 00000000..02ff7188
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.css
@@ -0,0 +1,42 @@
+.deck-prev-link, .deck-next-link {
+ display: none;
+ position: absolute;
+ z-index: 3;
+ top: 50%;
+ width: 32px;
+ height: 32px;
+ margin-top: -16px;
+ font-size: 20px;
+ font-weight: bold;
+ line-height: 32px;
+ vertical-align: middle;
+ text-align: center;
+ text-decoration: none;
+ color: #fff;
+ background: #888;
+ border-radius: 16px;
+}
+.deck-prev-link:hover, .deck-prev-link:focus, .deck-prev-link:active, .deck-prev-link:visited, .deck-next-link:hover, .deck-next-link:focus, .deck-next-link:active, .deck-next-link:visited {
+ color: #fff;
+}
+
+.deck-prev-link {
+ left: 8px;
+}
+
+.deck-next-link {
+ right: 8px;
+}
+
+.deck-container:hover .deck-prev-link, .deck-container:hover .deck-next-link {
+ display: block;
+}
+.deck-container:hover .deck-prev-link.deck-nav-disabled, .touch .deck-container:hover .deck-prev-link, .deck-container:hover .deck-next-link.deck-nav-disabled, .touch .deck-container:hover .deck-next-link {
+ display: none;
+}
+
+@media print {
+ .deck-prev-link, .deck-next-link {
+ display: none !important;
+ }
+}
diff --git a/doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.html b/doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.html
new file mode 100644
index 00000000..5237f4ae
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.html
@@ -0,0 +1,5 @@
+<!-- Place the following snippet at the bottom of the deck container. -->
+<div aria-role="navigation">
+ <a href="#" class="deck-prev-link" title="Previous">&#8592;</a>
+ <a href="#" class="deck-next-link" title="Next">&#8594;</a>
+</div>
diff --git a/doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.js b/doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.js
new file mode 100644
index 00000000..7dc95107
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.js
@@ -0,0 +1,94 @@
+/*!
+Deck JS - deck.navigation
+Copyright (c) 2011-2014 Caleb Troughton
+Dual licensed under the MIT license.
+https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt
+*/
+
+/*
+This module adds clickable previous and next links to the deck.
+*/
+(function($, undefined) {
+ var $document = $(document);
+
+ /* Updates link hrefs, and disabled states if last/first slide */
+ var updateButtons = function(event, from, to) {
+ var options = $.deck('getOptions');
+ var lastIndex = $.deck('getSlides').length - 1;
+ var $prevSlide = $.deck('getSlide', to - 1);
+ var $nextSlide = $.deck('getSlide', to + 1);
+ var hrefBase = window.location.href.replace(/#.*/, '');
+ var prevId = $prevSlide ? $prevSlide.attr('id') : undefined;
+ var nextId = $nextSlide ? $nextSlide.attr('id') : undefined;
+ var $prevButton = $(options.selectors.previousLink);
+ var $nextButton = $(options.selectors.nextLink);
+
+ $prevButton.toggleClass(options.classes.navDisabled, to === 0);
+ $prevButton.attr('aria-disabled', to === 0);
+ $prevButton.attr('href', hrefBase + '#' + (prevId ? prevId : ''));
+ $nextButton.toggleClass(options.classes.navDisabled, to === lastIndex);
+ $nextButton.attr('aria-disabled', to === lastIndex);
+ $nextButton.attr('href', hrefBase + '#' + (nextId ? nextId : ''));
+ };
+
+ /*
+ Extends defaults/options.
+
+ options.classes.navDisabled
+ This class is added to a navigation link when that action is disabled.
+ It is added to the previous link when on the first slide, and to the
+ next link when on the last slide.
+
+ options.selectors.nextLink
+ The elements that match this selector will move the deck to the next
+ slide when clicked.
+
+ options.selectors.previousLink
+ The elements that match this selector will move to deck to the previous
+ slide when clicked.
+ */
+ $.extend(true, $.deck.defaults, {
+ classes: {
+ navDisabled: 'deck-nav-disabled'
+ },
+
+ selectors: {
+ nextLink: '.deck-next-link',
+ previousLink: '.deck-prev-link'
+ }
+ });
+
+ $document.bind('deck.init', function() {
+ var options = $.deck('getOptions');
+ var slides = $.deck('getSlides');
+ var $current = $.deck('getSlide');
+ var $prevButton = $(options.selectors.previousLink);
+ var $nextButton = $(options.selectors.nextLink);
+ var index;
+
+ // Setup prev/next link events
+ $prevButton.unbind('click.decknavigation');
+ $prevButton.bind('click.decknavigation', function(event) {
+ $.deck('prev');
+ event.preventDefault();
+ });
+
+ $nextButton.unbind('click.decknavigation');
+ $nextButton.bind('click.decknavigation', function(event) {
+ $.deck('next');
+ event.preventDefault();
+ });
+
+ // Find where we started in the deck and set initial states
+ $.each(slides, function(i, $slide) {
+ if ($slide === $current) {
+ index = i;
+ return false;
+ }
+ });
+ updateButtons(null, index, index);
+ });
+
+ $document.bind('deck.change', updateButtons);
+})(jQuery);
+
diff --git a/doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.scss b/doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.scss
new file mode 100755
index 00000000..6c397746
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/navigation/deck.navigation.scss
@@ -0,0 +1,44 @@
+.deck-prev-link, .deck-next-link {
+ display:none;
+ position:absolute;
+ z-index:3;
+ top:50%;
+ width:32px;
+ height:32px;
+ margin-top:-16px;
+ font-size:20px;
+ font-weight:bold;
+ line-height:32px;
+ vertical-align:middle;
+ text-align:center;
+ text-decoration:none;
+ color:#fff;
+ background:#888;
+ border-radius:16px;
+
+ &:hover, &:focus, &:active, &:visited {
+ color:#fff;
+ }
+}
+
+.deck-prev-link {
+ left:8px;
+}
+
+.deck-next-link {
+ right:8px;
+}
+
+.deck-container:hover .deck-prev-link, .deck-container:hover .deck-next-link {
+ display:block;
+
+ &.deck-nav-disabled, .touch & {
+ display:none;
+ }
+}
+
+@media print {
+ .deck-prev-link, .deck-next-link {
+ display:none !important;
+ }
+}
diff --git a/doc/backends/deckjs/deck.js/extensions/scale/deck.scale.css b/doc/backends/deckjs/deck.js/extensions/scale/deck.scale.css
new file mode 100644
index 00000000..785e4033
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/scale/deck.scale.css
@@ -0,0 +1,20 @@
+.csstransforms .deck-container.deck-scale:not(.deck-menu) {
+ overflow: hidden;
+}
+.csstransforms .deck-container.deck-scale:not(.deck-menu) > .slide {
+ -moz-box-sizing: padding-box;
+ box-sizing: padding-box;
+ width: 100%;
+ padding-bottom: 20px;
+}
+.csstransforms .deck-container.deck-scale:not(.deck-menu) > .slide > .deck-slide-scaler {
+ -webkit-transform-origin: 50% 0;
+ -ms-transform-origin: 50% 0;
+ transform-origin: 50% 0;
+}
+
+.csstransforms .deck-container.deck-menu .deck-slide-scaler {
+ -webkit-transform: none !important;
+ -ms-transform: none !important;
+ transform: none !important;
+}
diff --git a/doc/backends/deckjs/deck.js/extensions/scale/deck.scale.js b/doc/backends/deckjs/deck.js/extensions/scale/deck.scale.js
new file mode 100644
index 00000000..0e216318
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/scale/deck.scale.js
@@ -0,0 +1,190 @@
+/*!
+Deck JS - deck.scale
+Copyright (c) 2011-2014 Caleb Troughton
+Dual licensed under the MIT license.
+https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt
+*/
+
+/*
+This module adds automatic scaling to the deck. Slides are scaled down
+using CSS transforms to fit within the deck container. If the container is
+big enough to hold the slides without scaling, no scaling occurs. The user
+can disable and enable scaling with a keyboard shortcut.
+
+Note: CSS transforms may make Flash videos render incorrectly. Presenters
+that need to use video may want to disable scaling to play them. HTML5 video
+works fine.
+*/
+(function($, undefined) {
+ var $document = $(document);
+ var $window = $(window);
+ var baseHeight, timer, rootSlides;
+
+ /*
+ Internal function to do all the dirty work of scaling the slides.
+ */
+ var scaleDeck = function() {
+ var options = $.deck('getOptions');
+ var $container = $.deck('getContainer');
+ var baseHeight = options.baseHeight;
+
+ if (!baseHeight) {
+ baseHeight = $container.height();
+ }
+
+ // Scale each slide down if necessary (but don't scale up)
+ $.each(rootSlides, function(i, $slide) {
+ var slideHeight = $slide.innerHeight();
+ var $scaler = $slide.find('.' + options.classes.scaleSlideWrapper);
+ var shouldScale = $container.hasClass(options.classes.scale);
+ var scale = shouldScale ? baseHeight / slideHeight : 1;
+
+ if (scale === 1) {
+ $scaler.css('transform', '');
+ }
+ else {
+ $scaler.css('transform', 'scale(' + scale + ')');
+ window.setTimeout(function() {
+ $container.scrollTop(0)
+ }, 1);
+ }
+ });
+ };
+
+ var populateRootSlides = function() {
+ var options = $.deck('getOptions');
+ var slideTest = $.map([
+ options.classes.before,
+ options.classes.previous,
+ options.classes.current,
+ options.classes.next,
+ options.classes.after
+ ], function(el, i) {
+ return '.' + el;
+ }).join(', ');
+
+ rootSlides = [];
+ $.each($.deck('getSlides'), function(i, $slide) {
+ var $parentSlides = $slide.parentsUntil(
+ options.selectors.container,
+ slideTest
+ );
+ if (!$parentSlides.length) {
+ rootSlides.push($slide);
+ }
+ });
+ };
+
+ var wrapRootSlideContent = function() {
+ var options = $.deck('getOptions');
+ var wrap = '<div class="' + options.classes.scaleSlideWrapper + '"/>';
+ $.each(rootSlides, function(i, $slide) {
+ $slide.children().wrapAll(wrap);
+ });
+ };
+
+ var scaleOnResizeAndLoad = function() {
+ var options = $.deck('getOptions');
+
+ $window.unbind('resize.deckscale');
+ $window.bind('resize.deckscale', function() {
+ window.clearTimeout(timer);
+ timer = window.setTimeout(scaleDeck, options.scaleDebounce);
+ });
+ $.deck('enableScale');
+ $window.unbind('load.deckscale');
+ $window.bind('load.deckscale', scaleDeck);
+ };
+
+ var bindKeyEvents = function() {
+ var options = $.deck('getOptions');
+ $document.unbind('keydown.deckscale');
+ $document.bind('keydown.deckscale', function(event) {
+ var isKey = event.which === options.keys.scale;
+ isKey = isKey || $.inArray(event.which, options.keys.scale) > -1;
+ if (isKey) {
+ $.deck('toggleScale');
+ event.preventDefault();
+ }
+ });
+ };
+
+ /*
+ Extends defaults/options.
+
+ options.classes.scale
+ This class is added to the deck container when scaling is enabled.
+ It is enabled by default when the module is included.
+
+ options.classes.scaleSlideWrapper
+ Scaling is done using a wrapper around the contents of each slide. This
+ class is applied to that wrapper.
+
+ options.keys.scale
+ The numeric keycode used to toggle enabling and disabling scaling.
+
+ options.baseHeight
+ When baseHeight is falsy, as it is by default, the deck is scaled in
+ proportion to the height of the deck container. You may instead specify
+ a height as a number of px, and slides will be scaled against this
+ height regardless of the container size.
+
+ options.scaleDebounce
+ Scaling on the browser resize event is debounced. This number is the
+ threshold in milliseconds. You can learn more about debouncing here:
+ http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
+
+ */
+ $.extend(true, $.deck.defaults, {
+ classes: {
+ scale: 'deck-scale',
+ scaleSlideWrapper: 'deck-slide-scaler'
+ },
+
+ keys: {
+ scale: 83 // s
+ },
+
+ baseHeight: null,
+ scaleDebounce: 200
+ });
+
+ /*
+ jQuery.deck('disableScale')
+
+ Disables scaling and removes the scale class from the deck container.
+ */
+ $.deck('extend', 'disableScale', function() {
+ $.deck('getContainer').removeClass($.deck('getOptions').classes.scale);
+ scaleDeck();
+ });
+
+ /*
+ jQuery.deck('enableScale')
+
+ Enables scaling and adds the scale class to the deck container.
+ */
+ $.deck('extend', 'enableScale', function() {
+ $.deck('getContainer').addClass($.deck('getOptions').classes.scale);
+ scaleDeck();
+ });
+
+ /*
+ jQuery.deck('toggleScale')
+
+ Toggles between enabling and disabling scaling.
+ */
+ $.deck('extend', 'toggleScale', function() {
+ var $container = $.deck('getContainer');
+ var isScaled = $container.hasClass($.deck('getOptions').classes.scale);
+ $.deck(isScaled? 'disableScale' : 'enableScale');
+ });
+
+ $document.bind('deck.init', function() {
+ populateRootSlides();
+ wrapRootSlideContent();
+ scaleOnResizeAndLoad();
+ bindKeyEvents();
+ });
+})(jQuery, 'deck', this);
+
diff --git a/doc/backends/deckjs/deck.js/extensions/scale/deck.scale.scss b/doc/backends/deckjs/deck.js/extensions/scale/deck.scale.scss
new file mode 100644
index 00000000..8909357a
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/scale/deck.scale.scss
@@ -0,0 +1,22 @@
+.csstransforms .deck-container.deck-scale:not(.deck-menu) {
+ overflow:hidden;
+
+ > .slide {
+ -moz-box-sizing: padding-box;
+ box-sizing: padding-box;
+ width:100%;
+ padding-bottom:20px;
+
+ > .deck-slide-scaler {
+ -webkit-transform-origin: 50% 0;
+ -ms-transform-origin: 50% 0;
+ transform-origin: 50% 0;
+ }
+ }
+}
+
+.csstransforms .deck-container.deck-menu .deck-slide-scaler {
+ -webkit-transform:none !important;
+ -ms-transform:none !important;
+ transform:none !important;
+} \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/extensions/split/README.md b/doc/backends/deckjs/deck.js/extensions/split/README.md
new file mode 100644
index 00000000..eb2e9c6d
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/split/README.md
@@ -0,0 +1,30 @@
+
+deck.split.js
+==============
+
+`deck.split.js` is a deckjs extension that helps you split long slide into
+multiple small slides.
+
+
+Installation
+------------
+
+Just drop the whole repo into deck.js's `extensions` directory, then include
+the script in your slide.
+
+
+Usage
+-----
+
+To split a long slide, you need to indicate position inside original slide by
+adding following line:
+
+```html
+<div style="page-break-after:always"></div>
+```
+
+Indeed, it could be any tag set with `page-break-after:always` style. Every
+time you add this line, a new slide with the same title will be created, so you
+can split your slide into pieces as much as you want.
+
+
diff --git a/doc/backends/deckjs/deck.js/extensions/split/deck.split.js b/doc/backends/deckjs/deck.js/extensions/split/deck.split.js
new file mode 100644
index 00000000..081035c4
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/split/deck.split.js
@@ -0,0 +1,59 @@
+/*!
+Deck JS - deck.split
+Copyright (c) 2012 Qingping Hou <dave2008713@gmail.com>
+ about.houqp.me
+Dual licensed under the MIT license and GPL license.
+https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt
+https://github.com/imakewebthings/deck.js/blob/master/GPL-license.txt
+*/
+
+/*
+This module splits a long slide into multiple slides.
+*/
+(function($, deck, undefined) {
+ var $d = $(document);
+
+ createEmptySlide = function(title_el) {
+ slide = $(document.createElement('section'));
+ slide.addClass('slide').append(title_el.clone());
+ return slide;
+ };
+
+ $d.bind('deck.beforeInit', function() {
+ $(".slide").each( function(i, slide) {
+ /* each slide */
+ var is_split = false,
+ prev_slide = $(slide),
+ /* extract title which will be added to each new slides */
+ title_el = prev_slide.children('h2'),
+ tmp_slide = createEmptySlide(title_el);
+
+ $(slide).children().each(function() {
+ /* for each element inside original slide */
+ var el = $(this);
+
+ if (el.css('page-break-after') == 'always') {
+ if (is_split) {
+ tmp_slide.insertAfter(prev_slide);
+ prev_slide = tmp_slide;
+ tmp_slide = createEmptySlide(title_el);
+ }
+ else {
+ /* find the first page break */
+ is_split = true;
+ }
+ }
+ else {
+ if (is_split) {
+ tmp_slide.append(el);
+ }
+ }
+ })
+ /* add remaining elements to a new slides */
+ if (is_split) {
+ tmp_slide.insertAfter(prev_slide);
+ }
+ });
+ })
+})(jQuery, 'deck');
+
diff --git a/doc/backends/deckjs/deck.js/extensions/status/deck.status.css b/doc/backends/deckjs/deck.js/extensions/status/deck.status.css
new file mode 100644
index 00000000..b2736464
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/status/deck.status.css
@@ -0,0 +1,18 @@
+.deck-status {
+ position: absolute;
+ bottom: 10px;
+ right: 5px;
+ color: #888;
+ z-index: 3;
+ margin: 0;
+}
+
+body > .deck-container .deck-status {
+ position: fixed;
+}
+
+@media print {
+ .deck-status {
+ display: none;
+ }
+}
diff --git a/doc/backends/deckjs/deck.js/extensions/status/deck.status.html b/doc/backends/deckjs/deck.js/extensions/status/deck.status.html
new file mode 100644
index 00000000..5ecea5e4
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/status/deck.status.html
@@ -0,0 +1,6 @@
+<!-- Place the following snippet at the bottom of the deck container. -->
+<p class="deck-status" aria-role="status">
+ <span class="deck-status-current"></span>
+ /
+ <span class="deck-status-total"></span>
+</p>
diff --git a/doc/backends/deckjs/deck.js/extensions/status/deck.status.js b/doc/backends/deckjs/deck.js/extensions/status/deck.status.js
new file mode 100644
index 00000000..dca0734f
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/status/deck.status.js
@@ -0,0 +1,108 @@
+/*!
+Deck JS - deck.status
+Copyright (c) 2011-2014 Caleb Troughton
+Dual licensed under the MIT license.
+https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt
+*/
+
+/*
+This module adds a (current)/(total) style status indicator to the deck.
+*/
+(function($, undefined) {
+ var $document = $(document);
+ var rootCounter;
+
+ var updateCurrent = function(event, from, to) {
+ var options = $.deck('getOptions');
+ var currentSlideNumber = to + 1;
+ if (!options.countNested) {
+ currentSlideNumber = $.deck('getSlide', to).data('rootSlide');
+ }
+ $(options.selectors.statusCurrent).text(currentSlideNumber);
+ };
+
+ var markRootSlides = function() {
+ var options = $.deck('getOptions');
+ var slideTest = $.map([
+ options.classes.before,
+ options.classes.previous,
+ options.classes.current,
+ options.classes.next,
+ options.classes.after
+ ], function(el, i) {
+ return '.' + el;
+ }).join(', ');
+
+ rootCounter = 0;
+ $.each($.deck('getSlides'), function(i, $slide) {
+ var $parentSlides = $slide.parentsUntil(
+ options.selectors.container,
+ slideTest
+ );
+
+ if ($parentSlides.length) {
+ $slide.data('rootSlide', $parentSlides.last().data('rootSlide'));
+ }
+ else {
+ ++rootCounter;
+ $slide.data('rootSlide', rootCounter);
+ }
+ });
+ };
+
+ var setInitialSlideNumber = function() {
+ var slides = $.deck('getSlides');
+ var $currentSlide = $.deck('getSlide');
+ var index;
+
+ $.each(slides, function(i, $slide) {
+ if ($slide === $currentSlide) {
+ index = i;
+ return false;
+ }
+ });
+ updateCurrent(null, index, index);
+ };
+
+ var setTotalSlideNumber = function() {
+ var options = $.deck('getOptions');
+ var slides = $.deck('getSlides');
+
+ if (options.countNested) {
+ $(options.selectors.statusTotal).text(slides.length);
+ }
+ else {
+ $(options.selectors.statusTotal).text(rootCounter);
+ }
+ };
+
+ /*
+ Extends defaults/options.
+
+ options.selectors.statusCurrent
+ The element matching this selector displays the current slide number.
+
+ options.selectors.statusTotal
+ The element matching this selector displays the total number of slides.
+
+ options.countNested
+ If false, only top level slides will be counted in the current and
+ total numbers.
+ */
+ $.extend(true, $.deck.defaults, {
+ selectors: {
+ statusCurrent: '.deck-status-current',
+ statusTotal: '.deck-status-total'
+ },
+
+ countNested: true
+ });
+
+ $document.bind('deck.init', function() {
+ markRootSlides();
+ setInitialSlideNumber();
+ setTotalSlideNumber();
+ });
+ $document.bind('deck.change', updateCurrent);
+})(jQuery, 'deck');
+
diff --git a/doc/backends/deckjs/deck.js/extensions/status/deck.status.scss b/doc/backends/deckjs/deck.js/extensions/status/deck.status.scss
new file mode 100755
index 00000000..d0722bfe
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/status/deck.status.scss
@@ -0,0 +1,18 @@
+.deck-status {
+ position:absolute;
+ bottom:10px;
+ right:5px;
+ color:#888;
+ z-index:3;
+ margin:0;
+}
+
+body > .deck-container .deck-status {
+ position:fixed;
+}
+
+@media print {
+ .deck-status {
+ display:none;
+ }
+}
diff --git a/doc/backends/deckjs/deck.js/extensions/toc/deck.toc.css b/doc/backends/deckjs/deck.js/extensions/toc/deck.toc.css
new file mode 100644
index 00000000..6ed25c4c
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/toc/deck.toc.css
@@ -0,0 +1,40 @@
+.deck-container .deck-toc {
+ position: absolute;
+ z-index: 40;
+ top: 0px;
+ bottom: 0px;
+ left: 0;
+ right: 55%;
+ padding: 0.625em;
+ display: none;
+ background: #ccc;
+ overflow-y: auto;
+ overflow-x: auto;
+ background-color: #DDE4EB;
+ border-right: #A9A9A9 solid 1px;
+ width: 500px; }
+ .deck-container .deck-toc ul {
+ list-style: none;
+ margin: 0px;
+ padding: 0px;
+ font-size: 1em; }
+ .deck-container .deck-toc ul li {
+ white-space: nowrap;
+ padding-left: 1.5em;
+ font-weight: normal; }
+ .deck-container .deck-toc ul li#toc-0 {
+ font-weight: bold;
+ padding-bottom: 1em;
+ padding-left: 0px; }
+ .deck-container .deck-toc a {
+ width: 100%;
+ display: block !important;
+ text-decoration: none;
+ color: #595959 !important; }
+
+.deck-toc-frame .deck-toc {
+ display: block; }
+
+@media print {
+ .deck-toc {
+ display: none; } }
diff --git a/doc/backends/deckjs/deck.js/extensions/toc/deck.toc.html b/doc/backends/deckjs/deck.js/extensions/toc/deck.toc.html
new file mode 100644
index 00000000..27b8cc26
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/toc/deck.toc.html
@@ -0,0 +1,12 @@
+<!-- Place the following snippet at the bottom of the deck container. -->
+
+<!-- this is for the toc panel -->
+<div class="deck-toc"></div>
+
+<!-- this is a toc status panel -->
+<table class="deck-toc-status">
+ <tr>
+ <td class="right deck-toc-h2">&nbsp;</td>
+ <td class="left deck-toc-h3">&nbsp;</td>
+ </tr>
+</table> \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/extensions/toc/deck.toc.js b/doc/backends/deckjs/deck.js/extensions/toc/deck.toc.js
new file mode 100644
index 00000000..b16bd6a9
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/toc/deck.toc.js
@@ -0,0 +1,271 @@
+/*!
+Deck JS - deck.toc
+Copyright (c) 2011 Remi BARRAQUAND
+Dual licensed under the MIT license and GPL license.
+https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt
+https://github.com/imakewebthings/deck.js/blob/master/GPL-license.txt
+*/
+
+/*
+This module provides a support for TOC to the deck.
+*/
+
+(function($, deck, undefined) {
+ var $d = $(document);
+ var $toc;
+
+ /*
+ Extends defaults/options.
+
+ options.classes.toc
+ This class is added to the deck container when showing the slide
+ toc.
+
+ options.keys.toc
+ The numeric keycode used to toggle between showing and hiding
+ the slide toc.
+
+ options.selectors.toc
+ The element matching this selector displays the toc.
+
+ options.selectors.tocTitle
+ The element matching this selector displays the current title
+ of the slide i.e the current h1.
+
+ options.selectors.tocSection
+ The element matching this selector displays the current section
+ of the slide i.e the current h2.
+
+ options.selectors.tocSubSection
+ The element matching this selector displays the current
+ subsection of the slide i.e the current h3.
+
+ options.selectors.tocSubSubSection
+ The element matching this selector displays the current
+ subsubsection of the slide i.e the current h4.
+ */
+ $.extend(true, $[deck].defaults, {
+ classes: {
+ toc: 'deck-toc-frame'
+ },
+
+ keys: {
+ toc: 84 // t
+ },
+
+ selectors: {
+ toc: '.deck-toc',
+ tocTitle: '.deck-toc-h1',
+ tocSection: '.deck-toc-h2',
+ tocSubSection: '.deck-toc-h3',
+ tocSubSubSection: '.deck-toc-h4',
+ tocStatus: '.deck-toc-status'
+ }
+ });
+
+ /*
+ jQuery.deck('showToc')
+
+ Shows the slide toc by adding the class specified by the toc class option
+ to the deck container.
+ */
+ $[deck]('extend', 'showToc', function() {
+ $[deck]('getContainer').addClass($[deck]('getOptions').classes.toc);
+ });
+
+ /*
+ jQuery.deck('hideToc')
+
+ Hides the slide toc by removing the class specified by the toc class
+ option from the deck container.
+ */
+ $[deck]('extend', 'hideToc', function() {
+ $[deck]('getContainer').removeClass($[deck]('getOptions').classes.toc);
+ });
+
+ /*
+ jQuery.deck('toggleToc')
+
+ Toggles between showing and hiding the TOC.
+ */
+ $[deck]('extend', 'toggleToc', function() {
+ $[deck]('getContainer').hasClass($[deck]('getOptions').classes.toc) ?
+ $[deck]('hideToc') : $[deck]('showToc');
+ });
+
+ /*
+ jQuery.deck('Init')
+ */
+ $d.bind('deck.init', function() {
+ var opts = $[deck]('getOptions');
+ var container = $[deck]('getContainer');
+
+ /* Bind key events */
+ $d.unbind('keydown.decktoc').bind('keydown.decktoc', function(e) {
+ if (e.which === opts.keys.toc || $.inArray(e.which, opts.keys.toc) > -1) {
+ $[deck]('toggleToc');
+ e.preventDefault();
+ }
+ });
+
+ /* Hide TOC panel when user click on container */
+ container.click(function(e){
+ $[deck]('hideToc');
+ });
+
+ /* Init TOC and append it to the document */
+ $toc = new TOC();
+ $($[deck]('getOptions').selectors.toc).append($toc.root);
+
+ /* Go through all slides */
+ $.each($[deck]('getSlides'), function(i, $el) {
+ var slide = $[deck]('getSlide',i);
+ //var tocElementFound = false;
+
+ /* If there is a toc item, push it in the TOC */
+ for(var level=1; level<6; level++) {
+ if( slide.find("h"+level).length > 0) {
+ var tocTitle = "";
+ var $tocElement = slide.find("h"+level+":first");
+ if( $tocElement.attr("title") != undefined && $tocElement.attr("title") != "") {
+ tocTitle = $tocElement.attr("title");
+ } else {
+ tocTitle = $tocElement.text();
+ }
+ $toc.push(level, tocTitle, slide);
+ $toc.tag(slide);
+ //tocElementFound = true;
+ }
+ }
+
+ /* Tag the slide with the current TOC level */
+ $toc.tag(slide);
+ });
+ })
+ /* Update current slide number with each change event */
+ .bind('deck.change', function(e, from, to) {
+ var opts = $[deck]('getOptions');
+ var slideTo = $[deck]('getSlide', to);
+ var container = $[deck]('getContainer');
+
+ if (container.hasClass($[deck]('getOptions').classes.toc)) {
+ container.scrollTop(slideTo.offset().top);
+ }
+
+ /* update toc status */
+ if( slideTo.data("toc") ) {
+ // reset
+ $(opts.selectors.tocTitle).text("");
+ $(opts.selectors.tocSection).text("");
+ $(opts.selectors.tocSubSection).text("");
+ $(opts.selectors.tocSubSubSection).text("");
+
+ if( slideTo.hasClass('hide-toc-status') ) {
+ $(opts.selectors.tocStatus).hide();
+ } else {
+ $(opts.selectors.tocStatus).show();
+ // update according to the current context
+ var $context = $toc.context(slideTo.data('toc'))
+ for(var level=1; level<=$context.length; level++) {
+ switch(level) {
+ case 1:
+ $(opts.selectors.tocTitle).text($context[level-1]);
+ break;
+ case 2:
+ $(opts.selectors.tocSection).text($context[level-1]);
+ break;
+ case 3:
+ $(opts.selectors.tocSubSection).text($context[level-1]);
+ break;
+ case 4:
+ $(opts.selectors.tocSubSubSection).text($context[level-1]);
+ break;
+ }
+ }
+ }
+ }
+ });
+
+ /*
+ Simple TOC manager (must be improved)
+ */
+ var TOC = function() {
+
+ this.root = $("<ul/>", {"class":"toc"});
+
+ /*
+ Push new item in the TOC
+
+ depth is the level (e.g. 1 for h1, 2 for h2, etc.)
+ title is the toc-item title
+ slide is the slide that provides the toc-element
+ */
+ this.push = function(depth,title,slide) {
+ inc(depth);
+
+ /* Create toc element */
+ var $tocElm = $("<li />", {
+ id: "toc-"+($c.join('-'))
+ }).data({ // keep track of the slide in case...
+ slide: slide,
+ title: title
+ }).append($("<a />", { // create an hyperlink
+ href: "#"+$(slide).attr('id'),
+ text: title
+ })).append($("<ul />"));
+
+ /* insert it at the right place */
+ var $target = this.root;
+ if( depth > 1) {
+ $target = ($target.find("li#toc-"+($c.slice(0,$c.length-1).join('-')))).children("ul");
+ }
+ $tocElm.appendTo($target);
+ };
+
+ /*
+ Tag the slide with the current TOC level.
+
+ slide is the slide to tag
+ */
+ this.tag = function(slide) {
+ slide.data({
+ toc: $c.slice(0)
+ });
+ }
+
+ /*
+ Get the current TOC context
+
+ path is the current path in the TOC
+ */
+ this.context = function(path) {
+ $context = new Array();
+ var $target = this.root;
+ for(var depth=0; depth<path.length; depth++) {
+ var tocElm = $target.find("li#toc-"+(path.slice(0,depth+1).join('-')))
+ $context.push(tocElm.data('title'));
+ $target = (tocElm).children("ul");
+ }
+
+ return $context;
+ }
+
+ /* cursor */
+ var $c = [-1];
+ function inc(depth) {
+ var current_depth = $c.length;
+ if(depth>current_depth) {
+ for(i=current_depth;i<depth;i++) {
+ $c.push(0);
+ }
+ } else if( current_depth>depth) {
+ for(i=depth;i<current_depth;i++) {
+ $c.pop();
+ $c[depth-1]++
+ }
+ } else {
+ $c[depth-1]++
+ }
+ }
+ }
+})(jQuery, 'deck'); \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/extensions/toc/deck.toc.scss b/doc/backends/deckjs/deck.js/extensions/toc/deck.toc.scss
new file mode 100644
index 00000000..bcb6c599
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/extensions/toc/deck.toc.scss
@@ -0,0 +1,54 @@
+.deck-container {
+ .deck-toc {
+ position: absolute;
+ z-index: 40;
+ top: 0px;
+ bottom: 0px;
+ left: 0;
+ right: 55%;
+ padding: 0.625em;
+ display: none;
+ background: #ccc;
+ overflow-y: auto;
+ overflow-x: auto;
+ background-color: #DDE4EB;
+ border-right: #A9A9A9 solid 1px;
+ width: 500px;
+
+ ul {
+ list-style: none;
+ margin: 0px;
+ padding: 0px;
+ font-size: 1em;
+
+ li {
+ white-space: nowrap;
+ padding-left: 1.5em;
+ font-weight: normal;
+
+ &#toc-0 {
+ font-weight: bold;
+ padding-bottom: 1em;
+ padding-left: 0px;
+ }
+ }
+ }
+
+ a {
+ width: 100%;
+ display: block !important;
+ text-decoration: none;
+ color: #595959 !important;
+ }
+ }
+}
+
+.deck-toc-frame .deck-toc {
+ display: block;
+}
+
+@media print {
+ .deck-toc {
+ display:none;
+ }
+} \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/introduction/index.html b/doc/backends/deckjs/deck.js/introduction/index.html
new file mode 100644
index 00000000..81a0214a
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/introduction/index.html
@@ -0,0 +1,215 @@
+<!DOCTYPE html>
+<!--[if lt IE 7]> <html class="no-js ie6" lang="en"> <![endif]-->
+<!--[if IE 7]> <html class="no-js ie7" lang="en"> <![endif]-->
+<!--[if IE 8]> <html class="no-js ie8" lang="en"> <![endif]-->
+<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+
+ <title>Getting Started with deck.js</title>
+
+ <meta name="description" content="A jQuery library for modern HTML presentations">
+ <meta name="author" content="Caleb Troughton">
+ <meta name="viewport" content="width=1024, user-scalable=no">
+
+ <!-- Core and extension CSS files -->
+ <link rel="stylesheet" media="screen" href="../core/deck.core.css">
+ <link rel="stylesheet" media="screen" href="../extensions/goto/deck.goto.css">
+ <link rel="stylesheet" media="screen" href="../extensions/menu/deck.menu.css">
+ <link rel="stylesheet" media="screen" href="../extensions/navigation/deck.navigation.css">
+ <link rel="stylesheet" media="screen" href="../extensions/status/deck.status.css">
+ <link rel="stylesheet" media="screen" href="../extensions/scale/deck.scale.css">
+
+ <!-- Style theme. More available in /themes/style/ or create your own. -->
+ <link rel="stylesheet" media="screen" href="../themes/style/web-2.0.css">
+
+ <!-- Transition theme. More available in /themes/transition/ or create your own. -->
+ <link rel="stylesheet" media="screen" href="../themes/transition/horizontal-slide.css">
+
+ <!-- Basic black and white print styles -->
+ <link rel="stylesheet" media="print" href="../core/print.css">
+
+ <script src="../modernizr.custom.js"></script>
+</head>
+
+<body>
+ <div class="deck-container">
+
+ <!-- Begin slides -->
+ <section class="slide" id="title-slide">
+ <h1>Getting Started with deck.js</h1>
+ </section>
+
+ <section class="slide" id="how-to-overview">
+ <h2>How to Make a Deck</h2>
+ <ol>
+ <li>
+ <h3>Write Slides</h3>
+ <p>Slide content is simple&nbsp;HTML.</p>
+ </li>
+ <li>
+ <h3>Choose Themes</h3>
+ <p>One for slide styles and one for deck&nbsp;transitions.</p>
+ </li>
+ <li>
+ <h3>Include Extensions</h3>
+ <p>Add extra functionality to your deck, or leave it stripped&nbsp;down.</p>
+ </li>
+ </ol>
+ </section>
+
+ <section class="slide" id="quick-start">
+ <h2>Quick Start</h2>
+ <p>When you <a href="https://github.com/imakewebthings/deck.js/archive/latest.zip">download</a> deck.js, it will include a file named <code>boilerplate.html</code>. You can immediately start editing slides in this page and viewing them in your web browser. Later on, when you are comfortable customizing the deck, you can edit the various pieces of the boilerplate or make your own to suit your needs.</p>
+ </section>
+
+ <section class="slide" id="markup">
+ <h2>The Markup</h2>
+ <p>Slides are just HTML elements with a class of <code>slide</code>.</p>
+ <pre><code>&lt;section class=&quot;slide&quot;&gt;
+ &lt;h2&gt;How to Make a Deck&lt;/h2&gt;
+ &lt;ol&gt;
+ &lt;li&gt;
+ &lt;h3&gt;Write Slides&lt;/h3&gt;
+ &lt;p&gt;Slide content is simple HTML.&lt;/p&gt;
+ &lt;/li&gt;
+ &lt;li&gt;
+ &lt;h3&gt;Choose Themes&lt;/h3&gt;
+ &lt;p&gt;One for slide styles and one for deck transitions.&lt;/p&gt;
+ &lt;/li&gt;
+ &hellip;
+ &lt;/ol&gt;
+&lt;/section&gt;</code></pre>
+ </section>
+
+ <section class="slide" id="themes">
+ <h2>Style Themes</h2>
+ <p>Customizes the colors, typography, and layout of slide&nbsp;content.</p>
+ <pre><code>&lt;link rel=&quot;stylesheet&quot; href=&quot;/path/to/css/style-theme.css&quot;&gt;</code></pre>
+ <h2>Transition Themes</h2>
+ <p>Defines transitions between slides using CSS3 transitions. Less capable browsers fall back to cutaways. But <strong>you</strong> aren&rsquo;t using <em>those</em> browsers to give your presentations, are&nbsp;you&hellip;</p>
+ <pre><code>&lt;link rel=&quot;stylesheet&quot; href=&quot;/path/to/css/transition-theme.css&quot;&gt;</code></pre>
+ </section>
+
+ <section class="slide" id="extensions">
+ <h2>Extensions</h2>
+ <p>Core gives you basic slide functionality with left and right arrow navigation, but you may want more. Here are the ones included in this&nbsp;deck:</p>
+
+ <ul>
+ <li class="slide" id="extensions-goto">
+ <strong>deck.goto</strong>: Adds a shortcut key to jump to any slide number. Hit g, type in the slide number, and hit&nbsp;enter.
+ </li>
+
+ <li class="slide" id="extensions-menu">
+ <strong>deck.menu</strong>: Adds a menu view, letting you see all slides in a grid. Hit m to toggle to menu view, continue navigating your deck, and hit m to return to normal view. Touch devices can double-tap the deck to switch between&nbsp;views.
+ </li>
+
+ <li class="slide" id="extensions-navigation">
+ <strong>deck.navigation</strong>: Adds clickable left and right buttons for the less keyboard&nbsp;inclined.
+ </li>
+
+ <li class="slide" id="extensions-status">
+ <strong>deck.status</strong>: Adds a page number indicator. (current/total)
+ </li>
+
+ <li class="slide" id="extensions-scale">
+ <strong>deck.scale</strong>: Scales each slide to fit within the deck container using CSS Transforms for those browsers that support them.
+ </li>
+ </ul>
+
+ <p class="slide" id="extension-folders">Each extension folder in the download package contains the necessary JavaScript, CSS, and HTML&nbsp;files. For a complete list of extension modules included in deck.js, check out the&nbsp;<a href="http://imakewebthings.github.com/deck.js/docs">documentation</a>.</p>
+ </section>
+
+ <section class="slide" id="nested">
+ <h2>Nested Slides</h2>
+ <p>That last slide had a few steps. To create substeps in slides, just nest them:</p>
+ <pre><code>&lt;section class=&quot;slide&quot;&gt;
+ &lt;h2&gt;Extensions&lt;/h2&gt;
+ &lt;p&gt;Core gives you basic slide functionality...&lt;/p&gt;
+ &lt;ul&gt;
+ &lt;li class=&quot;slide&quot;&gt;
+ &lt;h3&gt;deck.goto&lt;/h3&gt;
+ &lt;p&gt;Adds a shortcut key to jump to any slide number...&lt;/p&gt;
+ &lt;/li&gt;
+ &lt;li class=&quot;slide&quot;&gt;...&lt;/li&gt;
+ &lt;li class=&quot;slide&quot;&gt;...&lt;/li&gt;
+ &lt;li class=&quot;slide&quot;&gt;...&lt;/li&gt;
+ &lt;/ul&gt;
+&lt;/section&gt;</code></pre>
+ </section>
+
+ <section class="slide" id="elements-images">
+ <h2>Other Elements: Images</h2>
+ <img src="http://placekitten.com/600/375" alt="Kitties">
+ <pre><code>&lt;img src=&quot;http://placekitten.com/600/375&quot; alt=&quot;Kitties&quot;&gt;</code></pre>
+ </section>
+
+ <section class="slide" id="elements-blockquotes">
+ <h2>Other Elements: Blockquotes</h2>
+ <blockquote cite="http://example.org">
+ <p>Food is an important part of a balanced diet.</p>
+ <p><cite>Fran Lebowitz</cite></p>
+ </blockquote>
+ <pre><code>&lt;blockquote cite=&quot;http://example.org&quot;&gt;
+ &lt;p&gt;Food is an important part of a balanced diet.&lt;/p&gt;
+ &lt;p&gt;&lt;cite&gt;Fran Lebowitz&lt;/cite&gt;&lt;/p&gt;
+&lt;/blockquote&gt;</code></pre>
+ </section>
+
+
+ <section class="slide" id="elements-videos">
+ <h2>Other Elements: Video Embeds</h2>
+ <p>Embed videos from your favorite online video service or with an HTML5 video&nbsp;element.</p>
+
+ <iframe src="http://player.vimeo.com/video/1063136?title=0&amp;byline=0&amp;portrait=0" width="400" height="225" frameborder="0"></iframe>
+
+ <pre><code>&lt;iframe src=&quot;http://player.vimeo.com/video/1063136?title=0&amp;amp;byline=0&amp;amp;portrait=0&quot; width=&quot;400&quot; height=&quot;225&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;</code></pre>
+ </section>
+
+ <section class="slide" id="digging-deeper">
+ <h2>Digging Deeper</h2>
+ <p>If you want to learn about making your own themes, extending deck.js, and more, check out the&nbsp;<a href="../docs/">documentation</a>.</p>
+ </section>
+
+ <!-- deck.navigation snippet -->
+ <div aria-role="navigation">
+ <a href="#" class="deck-prev-link" title="Previous">&#8592;</a>
+ <a href="#" class="deck-next-link" title="Next">&#8594;</a>
+ </div>
+
+ <!-- deck.status snippet -->
+ <p class="deck-status" aria-role="status">
+ <span class="deck-status-current"></span>
+ /
+ <span class="deck-status-total"></span>
+ </p>
+
+ <!-- deck.goto snippet -->
+ <form action="." method="get" class="goto-form">
+ <label for="goto-slide">Go to slide:</label>
+ <input type="text" name="slidenum" id="goto-slide" list="goto-datalist">
+ <datalist id="goto-datalist"></datalist>
+ <input type="submit" value="Go">
+ </form>
+ </div>
+
+<script src="../jquery.min.js"></script>
+
+<!-- Deck Core and extensions -->
+<script src="../core/deck.core.js"></script>
+<script src="../extensions/menu/deck.menu.js"></script>
+<script src="../extensions/goto/deck.goto.js"></script>
+<script src="../extensions/status/deck.status.js"></script>
+<script src="../extensions/navigation/deck.navigation.js"></script>
+<script src="../extensions/scale/deck.scale.js"></script>
+
+<!-- Initialize the deck -->
+<script>
+$(function() {
+ $.deck('.slide');
+});
+</script>
+
+</body>
+</html>
diff --git a/doc/backends/deckjs/deck.js/jquery.min.js b/doc/backends/deckjs/deck.js/jquery.min.js
new file mode 100644
index 00000000..76d21a46
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/jquery.min.js
@@ -0,0 +1,6 @@
+/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
+//@ sourceMappingURL=jquery-1.10.2.min.map
+*/
+(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav></:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t
+}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Ct=/^(?:checkbox|radio)$/i,Nt=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle);
+u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=un(e,t),Pt.detach()),Gt[e]=n),n}function un(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,n){x.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(x.css(e,"display"))?x.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x.support.opacity||(x.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=x.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===x.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,n){return n?x.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,n){x.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?x(e).position()[n]+"px":r):t}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!x.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||x.css(e,"display"))},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(x.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Ct.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),x.param=function(e,n){var r,i=[],o=function(e,t){t=x.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var mn,yn,vn=x.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Cn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Nn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=x.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=o.href}catch(Ln){yn=a.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(T)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(l){var u;return o[l]=!0,x.each(e[l]||[],function(e,l){var c=l(n,r,i);return"string"!=typeof c||a||o[c]?a?!(u=c):t:(n.dataTypes.unshift(c),s(c),!1)}),u}return s(n.dataTypes[0])||!o["*"]&&s("*")}function _n(e,n){var r,i,o=x.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,l=e.indexOf(" ");return l>=0&&(i=e.slice(l,e.length),e=e.slice(0,l)),x.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&x.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?x("<div>").append(x.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Cn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?_n(_n(e,x.ajaxSettings),t):_n(x.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,l,u,c,p=x.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?x(f):x.event,h=x.Deferred(),g=x.Callbacks("once memory"),m=p.statusCode||{},y={},v={},b=0,w="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return b||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>b)for(t in e)m[t]=[m[t],e[t]];else C.always(e[C.status]);return this},abort:function(e){var t=e||w;return u&&u.abort(t),k(0,t),this}};if(h.promise(C).complete=g.add,C.success=C.done,C.error=C.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=x.trim(p.dataType||"*").toLowerCase().match(T)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?"80":"443"))===(mn[3]||("http:"===mn[1]?"80":"443")))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=x.param(p.data,p.traditional)),qn(An,p,n,C),2===b)return C;l=p.global,l&&0===x.active++&&x.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Nn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(x.lastModified[o]&&C.setRequestHeader("If-Modified-Since",x.lastModified[o]),x.etag[o]&&C.setRequestHeader("If-None-Match",x.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&C.setRequestHeader("Content-Type",p.contentType),C.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)C.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,C,p)===!1||2===b))return C.abort();w="abort";for(i in{success:1,error:1,complete:1})C[i](p[i]);if(u=qn(jn,p,n,C)){C.readyState=1,l&&d.trigger("ajaxSend",[C,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){C.abort("timeout")},p.timeout));try{b=1,u.send(y,k)}catch(N){if(!(2>b))throw N;k(-1,N)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,N=n;2!==b&&(b=2,s&&clearTimeout(s),u=t,a=i||"",C.readyState=e>0?4:0,c=e>=200&&300>e||304===e,r&&(w=Mn(p,C,r)),w=On(p,w,C,c),c?(p.ifModified&&(T=C.getResponseHeader("Last-Modified"),T&&(x.lastModified[o]=T),T=C.getResponseHeader("etag"),T&&(x.etag[o]=T)),204===e||"HEAD"===p.type?N="nocontent":304===e?N="notmodified":(N=w.state,y=w.data,v=w.error,c=!v)):(v=N,(e||!N)&&(N="error",0>e&&(e=0))),C.status=e,C.statusText=(n||N)+"",c?h.resolveWith(f,[y,N,C]):h.rejectWith(f,[C,N,v]),C.statusCode(m),m=t,l&&d.trigger(c?"ajaxSuccess":"ajaxError",[C,p,c?y:v]),g.fireWith(f,[C,N]),l&&(d.trigger("ajaxComplete",[C,p]),--x.active||x.event.trigger("ajaxStop")))}return C},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,n){return x.get(e,t,n,"script")}}),x.each(["get","post"],function(e,n){x[n]=function(e,r,i,o){return x.isFunction(r)&&(o=o||i,i=r,r=t),x.ajax({url:e,type:n,dataType:o,data:r,success:i})}});function Mn(e,n,r){var i,o,a,s,l=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in l)if(l[s]&&l[s].test(o)){u.unshift(s);break}if(u[0]in r)a=u[0];else{for(s in r){if(!u[0]||e.converters[s+" "+u[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==u[0]&&u.unshift(a),r[a]):t}function On(e,t,n,r){var i,o,a,s,l,u={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)u[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!l&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),l=o,o=c.shift())if("*"===o)o=l;else if("*"!==l&&l!==o){if(a=u[l+" "+o]||u["* "+o],!a)for(i in u)if(s=i.split(" "),s[1]===o&&(a=u[l+" "+s[0]]||u["* "+s[0]])){a===!0?a=u[i]:u[i]!==!0&&(o=s[0],c.unshift(s[1]));break}if(a!==!0)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(p){return{state:"parsererror",error:a?p:"No conversion from "+l+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),x.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=a.head||x("head")[0]||a.documentElement;return{send:function(t,i){n=a.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var Fn=[],Bn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Fn.pop()||x.expando+"_"+vn++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,l=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return l||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=x.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,l?n[l]=n[l].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||x.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,Fn.push(o)),s&&x.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}x.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=x.ajaxSettings.xhr(),x.support.cors=!!Rn&&"withCredentials"in Rn,Rn=x.support.ajax=!!Rn,Rn&&x.ajaxTransport(function(n){if(!n.crossDomain||x.support.cors){var r;return{send:function(i,o){var a,s,l=n.xhr();if(n.username?l.open(n.type,n.url,n.async,n.username,n.password):l.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)l[s]=n.xhrFields[s];n.mimeType&&l.overrideMimeType&&l.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)l.setRequestHeader(s,i[s])}catch(u){}l.send(n.hasContent&&n.data||null),r=function(e,i){var s,u,c,p;try{if(r&&(i||4===l.readyState))if(r=t,a&&(l.onreadystatechange=x.noop,$n&&delete Pn[a]),i)4!==l.readyState&&l.abort();else{p={},s=l.status,u=l.getAllResponseHeaders(),"string"==typeof l.responseText&&(p.text=l.responseText);try{c=l.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,u)},n.async?4===l.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},x(e).unload($n)),Pn[a]=r),l.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+w+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Yn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),a=(x.cssNumber[e]||"px"!==o&&+r)&&Yn.exec(x.css(n.elem,e)),s=1,l=20;if(a&&a[3]!==o){o=o||a[3],i=i||[],a=+r||1;do s=s||".5",a/=s,x.style(n.elem,e,a+o);while(s!==(s=n.cur()/r)&&1!==s&&--l)}return i&&(a=n.start=+a||+r||0,n.unit=o,n.end=i[1]?a+(i[1]+1)*i[2]:+i[2]),n}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=x.now()}function Zn(e,t,n){var r,i=(Qn[t]||[]).concat(Qn["*"]),o=0,a=i.length;for(;a>o;o++)if(r=i[o].call(n,t,e))return r}function er(e,t,n){var r,i,o=0,a=Gn.length,s=x.Deferred().always(function(){delete l.elem}),l=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,u.startTime+u.duration-t),r=n/u.duration||0,o=1-r,a=0,l=u.tweens.length;for(;l>a;a++)u.tweens[a].run(o);return s.notifyWith(e,[u,o,n]),1>o&&l?n:(s.resolveWith(e,[u]),!1)},u=s.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,u.opts,t,n,u.opts.specialEasing[t]||u.opts.easing);return u.tweens.push(r),r},stop:function(t){var n=0,r=t?u.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)u.tweens[n].run(1);return t?s.resolveWith(e,[u,t]):s.rejectWith(e,[u,t]),this}}),c=u.props;for(tr(c,u.opts.specialEasing);a>o;o++)if(r=Gn[o].call(u,e,c,u.opts))return r;return x.map(c,Zn,u),x.isFunction(u.opts.start)&&u.opts.start.call(e,u),x.fx.timer(x.extend(l,{elem:e,anim:u,queue:u.opts.queue})),u.progress(u.opts.progress).done(u.opts.done,u.opts.complete).fail(u.opts.fail).always(u.opts.always)}function tr(e,t){var n,r,i,o,a;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=x.cssHooks[r],a&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(er,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,l,u=this,c={},p=e.style,f=e.nodeType&&nn(e),d=x._data(e,"fxshow");n.queue||(s=x._queueHooks(e,"fx"),null==s.unqueued&&(s.unqueued=0,l=s.empty.fire,s.empty.fire=function(){s.unqueued||l()}),s.unqueued++,u.always(function(){u.always(function(){s.unqueued--,x.queue(e,"fx").length||s.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(x.support.inlineBlockNeedsLayout&&"inline"!==ln(e.nodeName)?p.zoom=1:p.display="inline-block")),n.overflow&&(p.overflow="hidden",x.support.shrinkWrapBlocks||u.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],Vn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show"))continue;c[r]=d&&d[r]||x.style(e,r)}if(!x.isEmptyObject(c)){d?"hidden"in d&&(f=d.hidden):d=x._data(e,"fxshow",{}),o&&(d.hidden=!f),f?x(e).show():u.done(function(){x(e).hide()}),u.done(function(){var t;x._removeData(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)a=Zn(f?d[r]:0,r,u),r in d||(d[r]=a.start,f&&(a.end=a.start,a.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}x.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),a=function(){var t=er(this,x.extend({},e),o);(i||x._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=x.timers,a=x._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=x._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,a=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=rr.prototype.init,x.fx.tick=function(){var e,n=x.timers,r=0;for(Xn=x.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||x.fx.stop(),Xn=t},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){Un||(Un=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(Un),Un=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){x.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,x.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},x.offset={setOffset:function(e,t,n){var r=x.css(e,"position");"static"===r&&(e.style.position="relative");var i=x(e),o=i.offset(),a=x.css(e,"top"),s=x.css(e,"left"),l=("absolute"===r||"fixed"===r)&&x.inArray("auto",[a,s])>-1,u={},c={},p,f;l?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),x.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(u.top=t.top-o.top+p),null!=t.left&&(u.left=t.left-o.left+f),"using"in t?t.using.call(e,u):i.css(u)}},x.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===x.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(n=e.offset()),n.top+=x.css(e[0],"borderTopWidth",!0),n.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-x.css(r,"marginTop",!0),left:t.left-n.left-x.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);x.fn[e]=function(i){return x.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?x(a).scrollLeft():o,r?o:x(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return x.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}x.each({Height:"height",Width:"width"},function(e,n){x.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){x.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return x.access(this,function(n,r,i){var o;return x.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?x.css(n,r,s):x.style(n,r,i,s)},n,a?i:t,a,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:(e.jQuery=e.$=x,"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}))})(window); \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/modernizr.custom.js b/doc/backends/deckjs/deck.js/modernizr.custom.js
new file mode 100644
index 00000000..964fb40a
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/modernizr.custom.js
@@ -0,0 +1,4 @@
+/* Modernizr 2.0.6 (Custom Build) | MIT & BSD
+ * Contains: fontface | backgroundsize | borderimage | borderradius | boxshadow | flexbox | hsla | multiplebgs | opacity | rgba | textshadow | cssanimations | csscolumns | generatedcontent | cssgradients | cssreflections | csstransforms | csstransforms3d | csstransitions | applicationcache | canvas | canvastext | draganddrop | hashchange | history | audio | video | indexeddb | input | inputtypes | localstorage | postmessage | sessionstorage | websockets | websqldatabase | webworkers | geolocation | inlinesvg | smil | svg | svgclippaths | touch | webgl | iepp | cssclasses | addtest | teststyles | testprop | testallprops | hasevent | prefixes | domprefixes | load
+ */
+;window.Modernizr=function(a,b,c){function H(){e.input=function(a){for(var b=0,c=a.length;b<c;b++)t[a[b]]=a[b]in l;return t}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" ")),e.inputtypes=function(a){for(var d=0,e,f,h,i=a.length;d<i;d++)l.setAttribute("type",f=a[d]),e=l.type!=="text",e&&(l.value=m,l.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(f)&&l.style.WebkitAppearance!==c?(g.appendChild(l),h=b.defaultView,e=h.getComputedStyle&&h.getComputedStyle(l,null).WebkitAppearance!=="textfield"&&l.offsetHeight!==0,g.removeChild(l)):/^(search|tel)$/.test(f)||(/^(url|email)$/.test(f)?e=l.checkValidity&&l.checkValidity()===!1:/^color$/.test(f)?(g.appendChild(l),g.offsetWidth,e=l.value!=m,g.removeChild(l)):e=l.value!=m)),s[a[d]]=!!e;return s}("search tel url email datetime date month week time datetime-local number range color".split(" "))}function F(a,b){var c=a.charAt(0).toUpperCase()+a.substr(1),d=(a+" "+p.join(c+" ")+c).split(" ");return E(d,b)}function E(a,b){for(var d in a)if(k[a[d]]!==c)return b=="pfx"?a[d]:!0;return!1}function D(a,b){return!!~(""+a).indexOf(b)}function C(a,b){return typeof a===b}function B(a,b){return A(o.join(a+";")+(b||""))}function A(a){k.cssText=a}var d="2.0.6",e={},f=!0,g=b.documentElement,h=b.head||b.getElementsByTagName("head")[0],i="modernizr",j=b.createElement(i),k=j.style,l=b.createElement("input"),m=":)",n=Object.prototype.toString,o=" -webkit- -moz- -o- -ms- -khtml- ".split(" "),p="Webkit Moz O ms Khtml".split(" "),q={svg:"http://www.w3.org/2000/svg"},r={},s={},t={},u=[],v=function(a,c,d,e){var f,h,j,k=b.createElement("div");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:i+(d+1),k.appendChild(j);f=["&shy;","<style>",a,"</style>"].join(""),k.id=i,k.innerHTML+=f,g.appendChild(k),h=c(k,a),k.parentNode.removeChild(k);return!!h},w=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=C(e[d],"function"),C(e[d],c)||(e[d]=c),e.removeAttribute(d))),e=null;return f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),x,y={}.hasOwnProperty,z;!C(y,c)&&!C(y.call,c)?z=function(a,b){return y.call(a,b)}:z=function(a,b){return b in a&&C(a.constructor.prototype[b],c)};var G=function(c,d){var f=c.join(""),g=d.length;v(f,function(c,d){var f=b.styleSheets[b.styleSheets.length-1],h=f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"",i=c.childNodes,j={};while(g--)j[i[g].id]=i[g];e.touch="ontouchstart"in a||j.touch.offsetTop===9,e.csstransforms3d=j.csstransforms3d.offsetLeft===9,e.generatedcontent=j.generatedcontent.offsetHeight>=1,e.fontface=/src/i.test(h)&&h.indexOf(d.split(" ")[0])===0},g,d)}(['@font-face {font-family:"font";src:url("https://")}',["@media (",o.join("touch-enabled),("),i,")","{#touch{top:9px;position:absolute}}"].join(""),["@media (",o.join("transform-3d),("),i,")","{#csstransforms3d{left:9px;position:absolute}}"].join(""),['#generatedcontent:after{content:"',m,'";visibility:hidden}'].join("")],["fontface","touch","csstransforms3d","generatedcontent"]);r.flexbox=function(){function c(a,b,c,d){a.style.cssText=o.join(b+":"+c+";")+(d||"")}function a(a,b,c,d){b+=":",a.style.cssText=(b+o.join(c+";"+b)).slice(0,-b.length)+(d||"")}var d=b.createElement("div"),e=b.createElement("div");a(d,"display","box","width:42px;padding:0;"),c(e,"box-flex","1","width:10px;"),d.appendChild(e),g.appendChild(d);var f=e.offsetWidth===42;d.removeChild(e),g.removeChild(d);return f},r.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},r.canvastext=function(){return!!e.canvas&&!!C(b.createElement("canvas").getContext("2d").fillText,"function")},r.webgl=function(){return!!a.WebGLRenderingContext},r.touch=function(){return e.touch},r.geolocation=function(){return!!navigator.geolocation},r.postmessage=function(){return!!a.postMessage},r.websqldatabase=function(){var b=!!a.openDatabase;return b},r.indexedDB=function(){for(var b=-1,c=p.length;++b<c;)if(a[p[b].toLowerCase()+"IndexedDB"])return!0;return!!a.indexedDB},r.hashchange=function(){return w("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},r.history=function(){return!!a.history&&!!history.pushState},r.draganddrop=function(){return w("dragstart")&&w("drop")},r.websockets=function(){for(var b=-1,c=p.length;++b<c;)if(a[p[b]+"WebSocket"])return!0;return"WebSocket"in a},r.rgba=function(){A("background-color:rgba(150,255,150,.5)");return D(k.backgroundColor,"rgba")},r.hsla=function(){A("background-color:hsla(120,40%,100%,.5)");return D(k.backgroundColor,"rgba")||D(k.backgroundColor,"hsla")},r.multiplebgs=function(){A("background:url(https://),url(https://),red url(https://)");return/(url\s*\(.*?){3}/.test(k.background)},r.backgroundsize=function(){return F("backgroundSize")},r.borderimage=function(){return F("borderImage")},r.borderradius=function(){return F("borderRadius")},r.boxshadow=function(){return F("boxShadow")},r.textshadow=function(){return b.createElement("div").style.textShadow===""},r.opacity=function(){B("opacity:.55");return/^0.55$/.test(k.opacity)},r.cssanimations=function(){return F("animationName")},r.csscolumns=function(){return F("columnCount")},r.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";A((a+o.join(b+a)+o.join(c+a)).slice(0,-a.length));return D(k.backgroundImage,"gradient")},r.cssreflections=function(){return F("boxReflect")},r.csstransforms=function(){return!!E(["transformProperty","WebkitTransform","MozTransform","OTransform","msTransform"])},r.csstransforms3d=function(){var a=!!E(["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"]);a&&"webkitPerspective"in g.style&&(a=e.csstransforms3d);return a},r.csstransitions=function(){return F("transitionProperty")},r.fontface=function(){return e.fontface},r.generatedcontent=function(){return e.generatedcontent},r.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType){c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"');var d='video/mp4; codecs="avc1.42E01E';c.h264=a.canPlayType(d+'"')||a.canPlayType(d+', mp4a.40.2"'),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"')}}catch(e){}return c},r.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"'),c.mp3=a.canPlayType("audio/mpeg;"),c.wav=a.canPlayType('audio/wav; codecs="1"'),c.m4a=a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")}catch(d){}return c},r.localstorage=function(){try{return!!localStorage.getItem}catch(a){return!1}},r.sessionstorage=function(){try{return!!sessionStorage.getItem}catch(a){return!1}},r.webworkers=function(){return!!a.Worker},r.applicationcache=function(){return!!a.applicationCache},r.svg=function(){return!!b.createElementNS&&!!b.createElementNS(q.svg,"svg").createSVGRect},r.inlinesvg=function(){var a=b.createElement("div");a.innerHTML="<svg/>";return(a.firstChild&&a.firstChild.namespaceURI)==q.svg},r.smil=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"animate")))},r.svgclippaths=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"clipPath")))};for(var I in r)z(r,I)&&(x=I.toLowerCase(),e[x]=r[I](),u.push((e[x]?"":"no-")+x));e.input||H(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)z(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return;b=typeof b=="boolean"?b:!!b(),g.className+=" "+(b?"":"no-")+a,e[a]=b}return e},A(""),j=l=null,a.attachEvent&&function(){var a=b.createElement("div");a.innerHTML="<elem></elem>";return a.childNodes.length!==1}()&&function(a,b){function s(a){var b=-1;while(++b<g)a.createElement(f[b])}a.iepp=a.iepp||{};var d=a.iepp,e=d.html5elements||"abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",f=e.split("|"),g=f.length,h=new RegExp("(^|\\s)("+e+")","gi"),i=new RegExp("<(/*)("+e+")","gi"),j=/^\s*[\{\}]\s*$/,k=new RegExp("(^|[^\\n]*?\\s)("+e+")([^\\n]*)({[\\n\\w\\W]*?})","gi"),l=b.createDocumentFragment(),m=b.documentElement,n=m.firstChild,o=b.createElement("body"),p=b.createElement("style"),q=/print|all/,r;d.getCSS=function(a,b){if(a+""===c)return"";var e=-1,f=a.length,g,h=[];while(++e<f){g=a[e];if(g.disabled)continue;b=g.media||b,q.test(b)&&h.push(d.getCSS(g.imports,b),g.cssText),b="all"}return h.join("")},d.parseCSS=function(a){var b=[],c;while((c=k.exec(a))!=null)b.push(((j.exec(c[1])?"\n":c[1])+c[2]+c[3]).replace(h,"$1.iepp_$2")+c[4]);return b.join("\n")},d.writeHTML=function(){var a=-1;r=r||b.body;while(++a<g){var c=b.getElementsByTagName(f[a]),d=c.length,e=-1;while(++e<d)c[e].className.indexOf("iepp_")<0&&(c[e].className+=" iepp_"+f[a])}l.appendChild(r),m.appendChild(o),o.className=r.className,o.id=r.id,o.innerHTML=r.innerHTML.replace(i,"<$1font")},d._beforePrint=function(){p.styleSheet.cssText=d.parseCSS(d.getCSS(b.styleSheets,"all")),d.writeHTML()},d.restoreHTML=function(){o.innerHTML="",m.removeChild(o),m.appendChild(r)},d._afterPrint=function(){d.restoreHTML(),p.styleSheet.cssText=""},s(b),s(l);d.disablePP||(n.insertBefore(p,n.firstChild),p.media="print",p.className="iepp-printshim",a.attachEvent("onbeforeprint",d._beforePrint),a.attachEvent("onafterprint",d._afterPrint))}(a,b),e._version=d,e._prefixes=o,e._domPrefixes=p,e.hasEvent=w,e.testProp=function(a){return E([a])},e.testAllProps=F,e.testStyles=v,g.className=g.className.replace(/\bno-js\b/,"")+(f?" js "+u.join(" "):"");return e}(this,this.document),function(a,b,c){function k(a){return!a||a=="loaded"||a=="complete"}function j(){var a=1,b=-1;while(p.length- ++b)if(p[b].s&&!(a=p[b].r))break;a&&g()}function i(a){var c=b.createElement("script"),d;c.src=a.s,c.onreadystatechange=c.onload=function(){!d&&k(c.readyState)&&(d=1,j(),c.onload=c.onreadystatechange=null)},m(function(){d||(d=1,j())},H.errorTimeout),a.e?c.onload():n.parentNode.insertBefore(c,n)}function h(a){var c=b.createElement("link"),d;c.href=a.s,c.rel="stylesheet",c.type="text/css";if(!a.e&&(w||r)){var e=function(a){m(function(){if(!d)try{a.sheet.cssRules.length?(d=1,j()):e(a)}catch(b){b.code==1e3||b.message=="security"||b.message=="denied"?(d=1,m(function(){j()},0)):e(a)}},0)};e(c)}else c.onload=function(){d||(d=1,m(function(){j()},0))},a.e&&c.onload();m(function(){d||(d=1,j())},H.errorTimeout),!a.e&&n.parentNode.insertBefore(c,n)}function g(){var a=p.shift();q=1,a?a.t?m(function(){a.t=="c"?h(a):i(a)},0):(a(),j()):q=0}function f(a,c,d,e,f,h){function i(){!o&&k(l.readyState)&&(r.r=o=1,!q&&j(),l.onload=l.onreadystatechange=null,m(function(){u.removeChild(l)},0))}var l=b.createElement(a),o=0,r={t:d,s:c,e:h};l.src=l.data=c,!s&&(l.style.display="none"),l.width=l.height="0",a!="object"&&(l.type=d),l.onload=l.onreadystatechange=i,a=="img"?l.onerror=i:a=="script"&&(l.onerror=function(){r.e=r.r=1,g()}),p.splice(e,0,r),u.insertBefore(l,s?null:n),m(function(){o||(u.removeChild(l),r.r=r.e=o=1,j())},H.errorTimeout)}function e(a,b,c){var d=b=="c"?z:y;q=0,b=b||"j",C(a)?f(d,a,b,this.i++,l,c):(p.splice(this.i++,0,a),p.length==1&&g());return this}function d(){var a=H;a.loader={load:e,i:0};return a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=r&&!s,u=s?l:n.parentNode,v=a.opera&&o.call(a.opera)=="[object Opera]",w="webkitAppearance"in l.style,x=w&&"async"in b.createElement("script"),y=r?"object":v||x?"img":"script",z=w?"img":y,A=Array.isArray||function(a){return o.call(a)=="[object Array]"},B=function(a){return Object(a)===a},C=function(a){return typeof a=="string"},D=function(a){return o.call(a)=="[object Function]"},E=[],F={},G,H;H=function(a){function f(a){var b=a.split("!"),c=E.length,d=b.pop(),e=b.length,f={url:d,origUrl:d,prefixes:b},g,h;for(h=0;h<e;h++)g=F[b[h]],g&&(f=g(f));for(h=0;h<c;h++)f=E[h](f);return f}function e(a,b,e,g,h){var i=f(a),j=i.autoCallback;if(!i.bypass){b&&(b=D(b)?b:b[a]||b[g]||b[a.split("/").pop().split("?")[0]]);if(i.instead)return i.instead(a,b,e,g,h);e.load(i.url,i.forceCSS||!i.forceJS&&/css$/.test(i.url)?"c":c,i.noexec),(D(b)||D(j))&&e.load(function(){d(),b&&b(i.origUrl,h,g),j&&j(i.origUrl,h,g)})}}function b(a,b){function c(a){if(C(a))e(a,h,b,0,d);else if(B(a))for(i in a)a.hasOwnProperty(i)&&e(a[i],h,b,i,d)}var d=!!a.test,f=d?a.yep:a.nope,g=a.load||a.both,h=a.callback,i;c(f),c(g),a.complete&&b.load(a.complete)}var g,h,i=this.yepnope.loader;if(C(a))e(a,0,i,0);else if(A(a))for(g=0;g<a.length;g++)h=a[g],C(h)?e(h,0,i,0):A(h)?H(h):B(h)&&b(h,i);else B(a)&&b(a,i)},H.addPrefix=function(a,b){F[a]=b},H.addFilter=function(a){E.push(a)},H.errorTimeout=1e4,b.readyState==null&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",G=function(){b.removeEventListener("DOMContentLoaded",G,0),b.readyState="complete"},0)),a.yepnope=d()}(this,this.document),Modernizr.load=function(){yepnope.apply(window,[].slice.call(arguments,0))}; \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/test/fixtures/empty.html b/doc/backends/deckjs/deck.js/test/fixtures/empty.html
new file mode 100644
index 00000000..cdadd2a4
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/fixtures/empty.html
@@ -0,0 +1,21 @@
+<div class="deck-container">
+ <div aria-role="navigation">
+ <a href="#" class="deck-prev-link">Previous</a>
+ <a href="#" class="deck-next-link">Next</a>
+ </div>
+
+ <p class="deck-status" aria-role="status">
+ <span class="deck-status-current"></span>
+ /
+ <span class="deck-status-total"></span>
+ </p>
+
+ <form action="." method="get" class="goto-form">
+ <label for="goto-slide">Go to slide:</label>
+ <input type="number" name="slidenum" id="goto-slide" value="">
+ <input type="submit" value="Go">
+ </form>
+
+ <a href="#" class="deck-permalink">#</a>
+ <a href="#custom-id" id="internal-test">Internal Test Link</a>
+</div>
diff --git a/doc/backends/deckjs/deck.js/test/fixtures/nesteds.html b/doc/backends/deckjs/deck.js/test/fixtures/nesteds.html
new file mode 100644
index 00000000..c3fb7c35
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/fixtures/nesteds.html
@@ -0,0 +1,36 @@
+<div class="deck-container">
+ <div class="slide toplevel">
+ </div>
+
+ <div class="slide toplevel">
+ </div>
+
+ <div class="slide root toplevel">
+ <div class="slide"></div>
+ <div class="slide"></div>
+ <div class="slide"></div>
+ <div class="slide">
+ <div class="slide"></div>
+ <div class="slide"></div>
+ <div class="slide"></div>
+ </div>
+ </div>
+
+ <div class="slide toplevel" id="after">
+ </div>
+
+ <div class="slide toplevel">
+ </div>
+
+ <p class="deck-status" aria-role="status">
+ <span class="deck-status-current"></span>
+ /
+ <span class="deck-status-total"></span>
+ </p>
+
+ <form action="." method="get" class="goto-form">
+ <label for="goto-slide">Go to slide:</label>
+ <input type="number" name="slidenum" id="goto-slide" value="">
+ <input type="submit" value="Go">
+ </form>
+</div>
diff --git a/doc/backends/deckjs/deck.js/test/fixtures/standard.html b/doc/backends/deckjs/deck.js/test/fixtures/standard.html
new file mode 100644
index 00000000..328ee7d3
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/fixtures/standard.html
@@ -0,0 +1,44 @@
+<div class="deck-container">
+ <div class="slide slide1"></div>
+
+ <div class="slide slide2" id="custom-id"></div>
+
+ <div class="slide slide3"></div>
+
+ <div class="slide slide4"></div>
+
+ <div class="slide slide5"></div>
+
+ <div aria-role="navigation">
+ <a href="#" class="deck-prev-link">Previous</a>
+ <a href="#" class="deck-next-link">Next</a>
+ </div>
+
+ <p class="deck-status" aria-role="status">
+ <span class="deck-status-current"></span>
+ /
+ <span class="deck-status-total"></span>
+ </p>
+
+ <form action="." method="get" class="goto-form">
+ <label for="goto-slide">Go to slide:</label>
+ <input type="number" name="slidenum" id="goto-slide" value="" list="goto-datalist">
+ <datalist id="goto-datalist"></datalist>
+ <input type="submit" value="Go">
+ </form>
+
+ <a href="#" class="deck-permalink">#</a>
+ <a href="#custom-id" id="internal-test">Internal Test Link</a>
+</div>
+
+<div class="alt-container">
+ <div class="alt-slide alt-slide1"><input></div>
+
+ <div class="alt-slide alt-slide2"></div>
+
+ <div class="alt-slide alt-slide3"></div>
+
+ <div class="alt-slide alt-slide4"></div>
+
+ <div class="alt-slide alt-slide5"></div>
+</div>
diff --git a/doc/backends/deckjs/deck.js/test/index.html b/doc/backends/deckjs/deck.js/test/index.html
new file mode 100644
index 00000000..f8454e83
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/index.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>deck.js - Jasmine Test Runner</title>
+ <link rel="stylesheet" type="text/css" href="lib/jasmine.css">
+ <script type="text/javascript" src="../modernizr.custom.js"></script>
+ <script type="text/javascript" src="lib/jasmine.js"></script>
+ <script type="text/javascript" src="lib/jasmine-html.js"></script>
+ <script src="../jquery.min.js"></script>
+ <script type="text/javascript" src="lib/jasmine-jquery.js"></script>
+
+ <!-- include source files here... -->
+ <script type="text/javascript" src="../core/deck.core.js"></script>
+ <script type="text/javascript" src="../extensions/menu/deck.menu.js"></script>
+ <script type="text/javascript" src="../extensions/goto/deck.goto.js"></script>
+ <script type="text/javascript" src="../extensions/status/deck.status.js"></script>
+ <script type="text/javascript" src="../extensions/navigation/deck.navigation.js"></script>
+ <script type="text/javascript" src="../extensions/scale/deck.scale.js"></script>
+
+ <!-- include spec files here... -->
+ <script type="text/javascript" src="settings.js"></script>
+ <script type="text/javascript" src="spec.core.js"></script>
+ <script type="text/javascript" src="spec.menu.js"></script>
+ <script type="text/javascript" src="spec.goto.js"></script>
+ <script type="text/javascript" src="spec.navigation.js"></script>
+ <script type="text/javascript" src="spec.status.js"></script>
+ <script type="text/javascript" src="spec.scale.js"></script>
+</head>
+
+<body>
+<script type="text/javascript">
+ jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
+ jasmine.getEnv().execute();
+</script>
+</body>
+</html>
diff --git a/doc/backends/deckjs/deck.js/test/lib/jasmine-html.js b/doc/backends/deckjs/deck.js/test/lib/jasmine-html.js
new file mode 100755
index 00000000..73834010
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/lib/jasmine-html.js
@@ -0,0 +1,190 @@
+jasmine.TrivialReporter = function(doc) {
+ this.document = doc || document;
+ this.suiteDivs = {};
+ this.logRunningSpecs = false;
+};
+
+jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) { el.appendChild(child); }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
+ var showPassed, showSkipped;
+
+ this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
+ this.createDom('div', { className: 'banner' },
+ this.createDom('div', { className: 'logo' },
+ this.createDom('span', { className: 'title' }, "Jasmine"),
+ this.createDom('span', { className: 'version' }, runner.env.versionString())),
+ this.createDom('div', { className: 'options' },
+ "Show ",
+ showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
+ showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
+ )
+ ),
+
+ this.runnerDiv = this.createDom('div', { className: 'runner running' },
+ this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
+ this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
+ this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
+ );
+
+ this.document.body.appendChild(this.outerDiv);
+
+ var suites = runner.suites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ var suiteDiv = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
+ this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
+ this.suiteDivs[suite.id] = suiteDiv;
+ var parentDiv = this.outerDiv;
+ if (suite.parentSuite) {
+ parentDiv = this.suiteDivs[suite.parentSuite.id];
+ }
+ parentDiv.appendChild(suiteDiv);
+ }
+
+ this.startedAt = new Date();
+
+ var self = this;
+ showPassed.onclick = function(evt) {
+ if (showPassed.checked) {
+ self.outerDiv.className += ' show-passed';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
+ }
+ };
+
+ showSkipped.onclick = function(evt) {
+ if (showSkipped.checked) {
+ self.outerDiv.className += ' show-skipped';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
+ }
+ };
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
+ var results = runner.results();
+ var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
+ this.runnerDiv.setAttribute("class", className);
+ //do it twice for IE
+ this.runnerDiv.setAttribute("className", className);
+ var specs = runner.specs();
+ var specCount = 0;
+ for (var i = 0; i < specs.length; i++) {
+ if (this.specFilter(specs[i])) {
+ specCount++;
+ }
+ }
+ var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
+ message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
+ this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
+
+ this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
+};
+
+jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
+ var results = suite.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.totalCount === 0) { // todo: change this to check results.skipped
+ status = 'skipped';
+ }
+ this.suiteDivs[suite.id].className += " " + status;
+};
+
+jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
+ if (this.logRunningSpecs) {
+ this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+};
+
+jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
+ var results = spec.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+ var specDiv = this.createDom('div', { className: 'spec ' + status },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(spec.getFullName()),
+ title: spec.getFullName()
+ }, spec.description));
+
+
+ var resultItems = results.getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ specDiv.appendChild(messagesDiv);
+ }
+
+ this.suiteDivs[spec.suite.id].appendChild(specDiv);
+};
+
+jasmine.TrivialReporter.prototype.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+};
+
+jasmine.TrivialReporter.prototype.getLocation = function() {
+ return this.document.location;
+};
+
+jasmine.TrivialReporter.prototype.specFilter = function(spec) {
+ var paramMap = {};
+ var params = this.getLocation().search.substring(1).split('&');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ if (!paramMap.spec) {
+ return true;
+ }
+ return spec.getFullName().indexOf(paramMap.spec) === 0;
+};
diff --git a/doc/backends/deckjs/deck.js/test/lib/jasmine-jquery.js b/doc/backends/deckjs/deck.js/test/lib/jasmine-jquery.js
new file mode 100755
index 00000000..4f7357df
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/lib/jasmine-jquery.js
@@ -0,0 +1,288 @@
+var readFixtures = function() {
+ return jasmine.getFixtures().proxyCallTo_('read', arguments);
+};
+
+var preloadFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('preload', arguments);
+};
+
+var loadFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('load', arguments);
+};
+
+var setFixtures = function(html) {
+ jasmine.getFixtures().set(html);
+};
+
+var sandbox = function(attributes) {
+ return jasmine.getFixtures().sandbox(attributes);
+};
+
+var spyOnEvent = function(selector, eventName) {
+ jasmine.JQuery.events.spyOn(selector, eventName);
+}
+
+jasmine.getFixtures = function() {
+ return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures();
+};
+
+jasmine.Fixtures = function() {
+ this.containerId = 'jasmine-fixtures';
+ this.fixturesCache_ = {};
+ this.fixturesPath = 'spec/javascripts/fixtures';
+};
+
+jasmine.Fixtures.prototype.set = function(html) {
+ this.cleanUp();
+ this.createContainer_(html);
+};
+
+jasmine.Fixtures.prototype.preload = function() {
+ this.read.apply(this, arguments);
+};
+
+jasmine.Fixtures.prototype.load = function() {
+ this.cleanUp();
+ this.createContainer_(this.read.apply(this, arguments));
+};
+
+jasmine.Fixtures.prototype.read = function() {
+ var htmlChunks = [];
+
+ var fixtureUrls = arguments;
+ for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
+ htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex]));
+ }
+
+ return htmlChunks.join('');
+};
+
+jasmine.Fixtures.prototype.clearCache = function() {
+ this.fixturesCache_ = {};
+};
+
+jasmine.Fixtures.prototype.cleanUp = function() {
+ jQuery('#' + this.containerId).remove();
+};
+
+jasmine.Fixtures.prototype.sandbox = function(attributes) {
+ var attributesToSet = attributes || {};
+ return jQuery('<div id="sandbox" />').attr(attributesToSet);
+};
+
+jasmine.Fixtures.prototype.createContainer_ = function(html) {
+ var container;
+ if(html instanceof jQuery) {
+ container = jQuery('<div id="' + this.containerId + '" />');
+ container.html(html);
+ } else {
+ container = '<div id="' + this.containerId + '">' + html + '</div>'
+ }
+ jQuery('body').append(container);
+};
+
+jasmine.Fixtures.prototype.getFixtureHtml_ = function(url) {
+ if (typeof this.fixturesCache_[url] == 'undefined') {
+ this.loadFixtureIntoCache_(url);
+ }
+ return this.fixturesCache_[url];
+};
+
+jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) {
+ var self = this;
+ var url = this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl;
+ jQuery.ajax({
+ async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
+ cache: false,
+ dataType: 'html',
+ url: url,
+ success: function(data) {
+ self.fixturesCache_[relativeUrl] = data;
+ },
+ error: function(jqXHR, status, errorThrown) {
+ throw Error('Fixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + errorThrown.message + ')');
+ }
+ });
+};
+
+jasmine.Fixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) {
+ return this[methodName].apply(this, passedArguments);
+};
+
+
+jasmine.JQuery = function() {};
+
+jasmine.JQuery.browserTagCaseIndependentHtml = function(html) {
+ return jQuery('<div/>').append(html).html();
+};
+
+jasmine.JQuery.elementToString = function(element) {
+ return jQuery('<div />').append(element.clone()).html();
+};
+
+jasmine.JQuery.matchersClass = {};
+
+(function(namespace) {
+ var data = {
+ spiedEvents: {},
+ handlers: []
+ };
+
+ namespace.events = {
+ spyOn: function(selector, eventName) {
+ var handler = function(e) {
+ data.spiedEvents[[selector, eventName]] = e;
+ };
+ jQuery(selector).bind(eventName, handler);
+ data.handlers.push(handler);
+ },
+
+ wasTriggered: function(selector, eventName) {
+ return !!(data.spiedEvents[[selector, eventName]]);
+ },
+
+ cleanUp: function() {
+ data.spiedEvents = {};
+ data.handlers = [];
+ }
+ }
+})(jasmine.JQuery);
+
+(function(){
+ var jQueryMatchers = {
+ toHaveClass: function(className) {
+ return this.actual.hasClass(className);
+ },
+
+ toBeVisible: function() {
+ return this.actual.is(':visible');
+ },
+
+ toBeHidden: function() {
+ return this.actual.is(':hidden');
+ },
+
+ toBeSelected: function() {
+ return this.actual.is(':selected');
+ },
+
+ toBeChecked: function() {
+ return this.actual.is(':checked');
+ },
+
+ toBeEmpty: function() {
+ return this.actual.is(':empty');
+ },
+
+ toExist: function() {
+ return this.actual.size() > 0;
+ },
+
+ toHaveAttr: function(attributeName, expectedAttributeValue) {
+ return hasProperty(this.actual.attr(attributeName), expectedAttributeValue);
+ },
+
+ toHaveId: function(id) {
+ return this.actual.attr('id') == id;
+ },
+
+ toHaveHtml: function(html) {
+ return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html);
+ },
+
+ toHaveText: function(text) {
+ if (text && jQuery.isFunction(text.test)) {
+ return text.test(this.actual.text());
+ } else {
+ return this.actual.text() == text;
+ }
+ },
+
+ toHaveValue: function(value) {
+ return this.actual.val() == value;
+ },
+
+ toHaveData: function(key, expectedValue) {
+ return hasProperty(this.actual.data(key), expectedValue);
+ },
+
+ toBe: function(selector) {
+ return this.actual.is(selector);
+ },
+
+ toContain: function(selector) {
+ return this.actual.find(selector).size() > 0;
+ },
+
+ toBeDisabled: function(selector){
+ return this.actual.is(':disabled');
+ },
+
+ // tests the existence of a specific event binding
+ toHandle: function(eventName) {
+ var events = this.actual.data("events");
+ return events && events[eventName].length > 0;
+ },
+
+ // tests the existence of a specific event binding + handler
+ toHandleWith: function(eventName, eventHandler) {
+ var stack = this.actual.data("events")[eventName];
+ var i;
+ for (i = 0; i < stack.length; i++) {
+ if (stack[i].handler == eventHandler) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ var hasProperty = function(actualValue, expectedValue) {
+ if (expectedValue === undefined) {
+ return actualValue !== undefined;
+ }
+ return actualValue == expectedValue;
+ };
+
+ var bindMatcher = function(methodName) {
+ var builtInMatcher = jasmine.Matchers.prototype[methodName];
+
+ jasmine.JQuery.matchersClass[methodName] = function() {
+ if (this.actual instanceof jQuery) {
+ var result = jQueryMatchers[methodName].apply(this, arguments);
+ this.actual = jasmine.JQuery.elementToString(this.actual);
+ return result;
+ }
+
+ if (builtInMatcher) {
+ return builtInMatcher.apply(this, arguments);
+ }
+
+ return false;
+ };
+ };
+
+ for(var methodName in jQueryMatchers) {
+ bindMatcher(methodName);
+ }
+})();
+
+beforeEach(function() {
+ this.addMatchers(jasmine.JQuery.matchersClass);
+ this.addMatchers({
+ toHaveBeenTriggeredOn: function(selector) {
+ this.message = function() {
+ return [
+ "Expected event " + this.actual + " to have been triggered on" + selector,
+ "Expected event " + this.actual + " not to have been triggered on" + selector
+ ];
+ };
+ return jasmine.JQuery.events.wasTriggered(selector, this.actual);
+ }
+ })
+});
+
+afterEach(function() {
+ jasmine.getFixtures().cleanUp();
+ jasmine.JQuery.events.cleanUp();
+});
diff --git a/doc/backends/deckjs/deck.js/test/lib/jasmine.css b/doc/backends/deckjs/deck.js/test/lib/jasmine.css
new file mode 100755
index 00000000..6583fe7c
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/lib/jasmine.css
@@ -0,0 +1,166 @@
+body {
+ font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
+}
+
+
+.jasmine_reporter a:visited, .jasmine_reporter a {
+ color: #303;
+}
+
+.jasmine_reporter a:hover, .jasmine_reporter a:active {
+ color: blue;
+}
+
+.run_spec {
+ float:right;
+ padding-right: 5px;
+ font-size: .8em;
+ text-decoration: none;
+}
+
+.jasmine_reporter {
+ margin: 0 5px;
+}
+
+.banner {
+ color: #303;
+ background-color: #fef;
+ padding: 5px;
+}
+
+.logo {
+ float: left;
+ font-size: 1.1em;
+ padding-left: 5px;
+}
+
+.logo .version {
+ font-size: .6em;
+ padding-left: 1em;
+}
+
+.runner.running {
+ background-color: yellow;
+}
+
+
+.options {
+ text-align: right;
+ font-size: .8em;
+}
+
+
+
+
+.suite {
+ border: 1px outset gray;
+ margin: 5px 0;
+ padding-left: 1em;
+}
+
+.suite .suite {
+ margin: 5px;
+}
+
+.suite.passed {
+ background-color: #dfd;
+}
+
+.suite.failed {
+ background-color: #fdd;
+}
+
+.spec {
+ margin: 5px;
+ padding-left: 1em;
+ clear: both;
+}
+
+.spec.failed, .spec.passed, .spec.skipped {
+ padding-bottom: 5px;
+ border: 1px solid gray;
+}
+
+.spec.failed {
+ background-color: #fbb;
+ border-color: red;
+}
+
+.spec.passed {
+ background-color: #bfb;
+ border-color: green;
+}
+
+.spec.skipped {
+ background-color: #bbb;
+}
+
+.messages {
+ border-left: 1px dashed gray;
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+.passed {
+ background-color: #cfc;
+ display: none;
+}
+
+.failed {
+ background-color: #fbb;
+}
+
+.skipped {
+ color: #777;
+ background-color: #eee;
+ display: none;
+}
+
+
+/*.resultMessage {*/
+ /*white-space: pre;*/
+/*}*/
+
+.resultMessage span.result {
+ display: block;
+ line-height: 2em;
+ color: black;
+}
+
+.resultMessage .mismatch {
+ color: black;
+}
+
+.stackTrace {
+ white-space: pre;
+ font-size: .8em;
+ margin-left: 10px;
+ max-height: 5em;
+ overflow: auto;
+ border: 1px inset red;
+ padding: 1em;
+ background: #eef;
+}
+
+.finished-at {
+ padding-left: 1em;
+ font-size: .6em;
+}
+
+.show-passed .passed,
+.show-skipped .skipped {
+ display: block;
+}
+
+
+#jasmine_content {
+ position:fixed;
+ right: 100%;
+}
+
+.runner {
+ border: 1px solid gray;
+ display: block;
+ margin: 5px 0;
+ padding: 2px 0 2px 10px;
+}
diff --git a/doc/backends/deckjs/deck.js/test/lib/jasmine.js b/doc/backends/deckjs/deck.js/test/lib/jasmine.js
new file mode 100755
index 00000000..e96e0a78
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/lib/jasmine.js
@@ -0,0 +1,2477 @@
+var isCommonJS = typeof window == "undefined";
+
+/**
+ * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
+ *
+ * @namespace
+ */
+var jasmine = {};
+if (isCommonJS) exports.jasmine = jasmine;
+/**
+ * @private
+ */
+jasmine.unimplementedMethod_ = function() {
+ throw new Error("unimplemented method");
+};
+
+/**
+ * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
+ * a plain old variable and may be redefined by somebody else.
+ *
+ * @private
+ */
+jasmine.undefined = jasmine.___undefined___;
+
+/**
+ * Show diagnostic messages in the console if set to true
+ *
+ */
+jasmine.VERBOSE = false;
+
+/**
+ * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
+ *
+ */
+jasmine.DEFAULT_UPDATE_INTERVAL = 250;
+
+/**
+ * Default timeout interval in milliseconds for waitsFor() blocks.
+ */
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+jasmine.getGlobal = function() {
+ function getGlobal() {
+ return this;
+ }
+
+ return getGlobal();
+};
+
+/**
+ * Allows for bound functions to be compared. Internal use only.
+ *
+ * @ignore
+ * @private
+ * @param base {Object} bound 'this' for the function
+ * @param name {Function} function to find
+ */
+jasmine.bindOriginal_ = function(base, name) {
+ var original = base[name];
+ if (original.apply) {
+ return function() {
+ return original.apply(base, arguments);
+ };
+ } else {
+ // IE support
+ return jasmine.getGlobal()[name];
+ }
+};
+
+jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
+jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
+jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
+jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
+
+jasmine.MessageResult = function(values) {
+ this.type = 'log';
+ this.values = values;
+ this.trace = new Error(); // todo: test better
+};
+
+jasmine.MessageResult.prototype.toString = function() {
+ var text = "";
+ for (var i = 0; i < this.values.length; i++) {
+ if (i > 0) text += " ";
+ if (jasmine.isString_(this.values[i])) {
+ text += this.values[i];
+ } else {
+ text += jasmine.pp(this.values[i]);
+ }
+ }
+ return text;
+};
+
+jasmine.ExpectationResult = function(params) {
+ this.type = 'expect';
+ this.matcherName = params.matcherName;
+ this.passed_ = params.passed;
+ this.expected = params.expected;
+ this.actual = params.actual;
+ this.message = this.passed_ ? 'Passed.' : params.message;
+
+ var trace = (params.trace || new Error(this.message));
+ this.trace = this.passed_ ? '' : trace;
+};
+
+jasmine.ExpectationResult.prototype.toString = function () {
+ return this.message;
+};
+
+jasmine.ExpectationResult.prototype.passed = function () {
+ return this.passed_;
+};
+
+/**
+ * Getter for the Jasmine environment. Ensures one gets created
+ */
+jasmine.getEnv = function() {
+ var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
+ return env;
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isArray_ = function(value) {
+ return jasmine.isA_("Array", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isString_ = function(value) {
+ return jasmine.isA_("String", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isNumber_ = function(value) {
+ return jasmine.isA_("Number", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param {String} typeName
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isA_ = function(typeName, value) {
+ return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+};
+
+/**
+ * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
+ *
+ * @param value {Object} an object to be outputted
+ * @returns {String}
+ */
+jasmine.pp = function(value) {
+ var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
+ stringPrettyPrinter.format(value);
+ return stringPrettyPrinter.string;
+};
+
+/**
+ * Returns true if the object is a DOM Node.
+ *
+ * @param {Object} obj object to check
+ * @returns {Boolean}
+ */
+jasmine.isDomNode = function(obj) {
+ return obj.nodeType > 0;
+};
+
+/**
+ * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
+ *
+ * @example
+ * // don't care about which function is passed in, as long as it's a function
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
+ *
+ * @param {Class} clazz
+ * @returns matchable object of the type clazz
+ */
+jasmine.any = function(clazz) {
+ return new jasmine.Matchers.Any(clazz);
+};
+
+/**
+ * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
+ *
+ * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
+ * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
+ *
+ * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
+ *
+ * Spies are torn down at the end of every spec.
+ *
+ * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
+ *
+ * @example
+ * // a stub
+ * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
+ *
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // actual foo.not will not be called, execution stops
+ * spyOn(foo, 'not');
+
+ // foo.not spied upon, execution will continue to implementation
+ * spyOn(foo, 'not').andCallThrough();
+ *
+ * // fake example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // foo.not(val) will return val
+ * spyOn(foo, 'not').andCallFake(function(value) {return value;});
+ *
+ * // mock example
+ * foo.not(7 == 7);
+ * expect(foo.not).toHaveBeenCalled();
+ * expect(foo.not).toHaveBeenCalledWith(true);
+ *
+ * @constructor
+ * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
+ * @param {String} name
+ */
+jasmine.Spy = function(name) {
+ /**
+ * The name of the spy, if provided.
+ */
+ this.identity = name || 'unknown';
+ /**
+ * Is this Object a spy?
+ */
+ this.isSpy = true;
+ /**
+ * The actual function this spy stubs.
+ */
+ this.plan = function() {
+ };
+ /**
+ * Tracking of the most recent call to the spy.
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy.mostRecentCall.args = [1, 2];
+ */
+ this.mostRecentCall = {};
+
+ /**
+ * Holds arguments for each call to the spy, indexed by call count
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy(7, 8);
+ * mySpy.mostRecentCall.args = [7, 8];
+ * mySpy.argsForCall[0] = [1, 2];
+ * mySpy.argsForCall[1] = [7, 8];
+ */
+ this.argsForCall = [];
+ this.calls = [];
+};
+
+/**
+ * Tells a spy to call through to the actual implemenatation.
+ *
+ * @example
+ * var foo = {
+ * bar: function() { // do some stuff }
+ * }
+ *
+ * // defining a spy on an existing property: foo.bar
+ * spyOn(foo, 'bar').andCallThrough();
+ */
+jasmine.Spy.prototype.andCallThrough = function() {
+ this.plan = this.originalValue;
+ return this;
+};
+
+/**
+ * For setting the return value of a spy.
+ *
+ * @example
+ * // defining a spy from scratch: foo() returns 'baz'
+ * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() returns 'baz'
+ * spyOn(foo, 'bar').andReturn('baz');
+ *
+ * @param {Object} value
+ */
+jasmine.Spy.prototype.andReturn = function(value) {
+ this.plan = function() {
+ return value;
+ };
+ return this;
+};
+
+/**
+ * For throwing an exception when a spy is called.
+ *
+ * @example
+ * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
+ * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
+ * spyOn(foo, 'bar').andThrow('baz');
+ *
+ * @param {String} exceptionMsg
+ */
+jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
+ this.plan = function() {
+ throw exceptionMsg;
+ };
+ return this;
+};
+
+/**
+ * Calls an alternate implementation when a spy is called.
+ *
+ * @example
+ * var baz = function() {
+ * // do some stuff, return something
+ * }
+ * // defining a spy from scratch: foo() calls the function baz
+ * var foo = jasmine.createSpy('spy on foo').andCall(baz);
+ *
+ * // defining a spy on an existing property: foo.bar() calls an anonymnous function
+ * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
+ *
+ * @param {Function} fakeFunc
+ */
+jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
+ this.plan = fakeFunc;
+ return this;
+};
+
+/**
+ * Resets all of a spy's the tracking variables so that it can be used again.
+ *
+ * @example
+ * spyOn(foo, 'bar');
+ *
+ * foo.bar();
+ *
+ * expect(foo.bar.callCount).toEqual(1);
+ *
+ * foo.bar.reset();
+ *
+ * expect(foo.bar.callCount).toEqual(0);
+ */
+jasmine.Spy.prototype.reset = function() {
+ this.wasCalled = false;
+ this.callCount = 0;
+ this.argsForCall = [];
+ this.calls = [];
+ this.mostRecentCall = {};
+};
+
+jasmine.createSpy = function(name) {
+
+ var spyObj = function() {
+ spyObj.wasCalled = true;
+ spyObj.callCount++;
+ var args = jasmine.util.argsToArray(arguments);
+ spyObj.mostRecentCall.object = this;
+ spyObj.mostRecentCall.args = args;
+ spyObj.argsForCall.push(args);
+ spyObj.calls.push({object: this, args: args});
+ return spyObj.plan.apply(this, arguments);
+ };
+
+ var spy = new jasmine.Spy(name);
+
+ for (var prop in spy) {
+ spyObj[prop] = spy[prop];
+ }
+
+ spyObj.reset();
+
+ return spyObj;
+};
+
+/**
+ * Determines whether an object is a spy.
+ *
+ * @param {jasmine.Spy|Object} putativeSpy
+ * @returns {Boolean}
+ */
+jasmine.isSpy = function(putativeSpy) {
+ return putativeSpy && putativeSpy.isSpy;
+};
+
+/**
+ * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
+ * large in one call.
+ *
+ * @param {String} baseName name of spy class
+ * @param {Array} methodNames array of names of methods to make spies
+ */
+jasmine.createSpyObj = function(baseName, methodNames) {
+ if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
+ throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
+ }
+ var obj = {};
+ for (var i = 0; i < methodNames.length; i++) {
+ obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
+ }
+ return obj;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
+ *
+ * Be careful not to leave calls to <code>jasmine.log</code> in production code.
+ */
+jasmine.log = function() {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.log.apply(spec, arguments);
+};
+
+/**
+ * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
+ *
+ * @example
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
+ *
+ * @see jasmine.createSpy
+ * @param obj
+ * @param methodName
+ * @returns a Jasmine spy that can be chained with all spy methods
+ */
+var spyOn = function(obj, methodName) {
+ return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
+};
+if (isCommonJS) exports.spyOn = spyOn;
+
+/**
+ * Creates a Jasmine spec that will be added to the current suite.
+ *
+ * // TODO: pending tests
+ *
+ * @example
+ * it('should be true', function() {
+ * expect(true).toEqual(true);
+ * });
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var it = function(desc, func) {
+ return jasmine.getEnv().it(desc, func);
+};
+if (isCommonJS) exports.it = it;
+
+/**
+ * Creates a <em>disabled</em> Jasmine spec.
+ *
+ * A convenience method that allows existing specs to be disabled temporarily during development.
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var xit = function(desc, func) {
+ return jasmine.getEnv().xit(desc, func);
+};
+if (isCommonJS) exports.xit = xit;
+
+/**
+ * Starts a chain for a Jasmine expectation.
+ *
+ * It is passed an Object that is the actual value and should chain to one of the many
+ * jasmine.Matchers functions.
+ *
+ * @param {Object} actual Actual value to test against and expected value
+ */
+var expect = function(actual) {
+ return jasmine.getEnv().currentSpec.expect(actual);
+};
+if (isCommonJS) exports.expect = expect;
+
+/**
+ * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
+ *
+ * @param {Function} func Function that defines part of a jasmine spec.
+ */
+var runs = function(func) {
+ jasmine.getEnv().currentSpec.runs(func);
+};
+if (isCommonJS) exports.runs = runs;
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+var waits = function(timeout) {
+ jasmine.getEnv().currentSpec.waits(timeout);
+};
+if (isCommonJS) exports.waits = waits;
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
+};
+if (isCommonJS) exports.waitsFor = waitsFor;
+
+/**
+ * A function that is called before each spec in a suite.
+ *
+ * Used for spec setup, including validating assumptions.
+ *
+ * @param {Function} beforeEachFunction
+ */
+var beforeEach = function(beforeEachFunction) {
+ jasmine.getEnv().beforeEach(beforeEachFunction);
+};
+if (isCommonJS) exports.beforeEach = beforeEach;
+
+/**
+ * A function that is called after each spec in a suite.
+ *
+ * Used for restoring any state that is hijacked during spec execution.
+ *
+ * @param {Function} afterEachFunction
+ */
+var afterEach = function(afterEachFunction) {
+ jasmine.getEnv().afterEach(afterEachFunction);
+};
+if (isCommonJS) exports.afterEach = afterEach;
+
+/**
+ * Defines a suite of specifications.
+ *
+ * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
+ * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
+ * of setup in some tests.
+ *
+ * @example
+ * // TODO: a simple suite
+ *
+ * // TODO: a simple suite with a nested describe block
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var describe = function(description, specDefinitions) {
+ return jasmine.getEnv().describe(description, specDefinitions);
+};
+if (isCommonJS) exports.describe = describe;
+
+/**
+ * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var xdescribe = function(description, specDefinitions) {
+ return jasmine.getEnv().xdescribe(description, specDefinitions);
+};
+if (isCommonJS) exports.xdescribe = xdescribe;
+
+
+// Provide the XMLHttpRequest class for IE 5.x-6.x:
+jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
+ function tryIt(f) {
+ try {
+ return f();
+ } catch(e) {
+ }
+ return null;
+ }
+
+ var xhr = tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.6.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.3.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ });
+
+ if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
+
+ return xhr;
+} : XMLHttpRequest;
+/**
+ * @namespace
+ */
+jasmine.util = {};
+
+/**
+ * Declare that a child class inherit it's prototype from the parent class.
+ *
+ * @private
+ * @param {Function} childClass
+ * @param {Function} parentClass
+ */
+jasmine.util.inherit = function(childClass, parentClass) {
+ /**
+ * @private
+ */
+ var subclass = function() {
+ };
+ subclass.prototype = parentClass.prototype;
+ childClass.prototype = new subclass();
+};
+
+jasmine.util.formatException = function(e) {
+ var lineNumber;
+ if (e.line) {
+ lineNumber = e.line;
+ }
+ else if (e.lineNumber) {
+ lineNumber = e.lineNumber;
+ }
+
+ var file;
+
+ if (e.sourceURL) {
+ file = e.sourceURL;
+ }
+ else if (e.fileName) {
+ file = e.fileName;
+ }
+
+ var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
+
+ if (file && lineNumber) {
+ message += ' in ' + file + ' (line ' + lineNumber + ')';
+ }
+
+ return message;
+};
+
+jasmine.util.htmlEscape = function(str) {
+ if (!str) return str;
+ return str.replace(/&/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;');
+};
+
+jasmine.util.argsToArray = function(args) {
+ var arrayOfArgs = [];
+ for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
+ return arrayOfArgs;
+};
+
+jasmine.util.extend = function(destination, source) {
+ for (var property in source) destination[property] = source[property];
+ return destination;
+};
+
+/**
+ * Environment for Jasmine
+ *
+ * @constructor
+ */
+jasmine.Env = function() {
+ this.currentSpec = null;
+ this.currentSuite = null;
+ this.currentRunner_ = new jasmine.Runner(this);
+
+ this.reporter = new jasmine.MultiReporter();
+
+ this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
+ this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
+ this.lastUpdate = 0;
+ this.specFilter = function() {
+ return true;
+ };
+
+ this.nextSpecId_ = 0;
+ this.nextSuiteId_ = 0;
+ this.equalityTesters_ = [];
+
+ // wrap matchers
+ this.matchersClass = function() {
+ jasmine.Matchers.apply(this, arguments);
+ };
+ jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
+
+ jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
+};
+
+
+jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
+jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
+jasmine.Env.prototype.setInterval = jasmine.setInterval;
+jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
+
+/**
+ * @returns an object containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.version = function () {
+ if (jasmine.version_) {
+ return jasmine.version_;
+ } else {
+ throw new Error('Version not set');
+ }
+};
+
+/**
+ * @returns string containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.versionString = function() {
+ if (!jasmine.version_) {
+ return "version unknown";
+ }
+
+ var version = this.version();
+ var versionString = version.major + "." + version.minor + "." + version.build;
+ if (version.release_candidate) {
+ versionString += ".rc" + version.release_candidate
+ }
+ versionString += " revision " + version.revision;
+ return versionString;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSpecId = function () {
+ return this.nextSpecId_++;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSuiteId = function () {
+ return this.nextSuiteId_++;
+};
+
+/**
+ * Register a reporter to receive status updates from Jasmine.
+ * @param {jasmine.Reporter} reporter An object which will receive status updates.
+ */
+jasmine.Env.prototype.addReporter = function(reporter) {
+ this.reporter.addReporter(reporter);
+};
+
+jasmine.Env.prototype.execute = function() {
+ this.currentRunner_.execute();
+};
+
+jasmine.Env.prototype.describe = function(description, specDefinitions) {
+ var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
+
+ var parentSuite = this.currentSuite;
+ if (parentSuite) {
+ parentSuite.add(suite);
+ } else {
+ this.currentRunner_.add(suite);
+ }
+
+ this.currentSuite = suite;
+
+ var declarationError = null;
+ try {
+ specDefinitions.call(suite);
+ } catch(e) {
+ declarationError = e;
+ }
+
+ if (declarationError) {
+ this.it("encountered a declaration exception", function() {
+ throw declarationError;
+ });
+ }
+
+ this.currentSuite = parentSuite;
+
+ return suite;
+};
+
+jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.beforeEach(beforeEachFunction);
+ } else {
+ this.currentRunner_.beforeEach(beforeEachFunction);
+ }
+};
+
+jasmine.Env.prototype.currentRunner = function () {
+ return this.currentRunner_;
+};
+
+jasmine.Env.prototype.afterEach = function(afterEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.afterEach(afterEachFunction);
+ } else {
+ this.currentRunner_.afterEach(afterEachFunction);
+ }
+
+};
+
+jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
+ return {
+ execute: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.it = function(description, func) {
+ var spec = new jasmine.Spec(this, this.currentSuite, description);
+ this.currentSuite.add(spec);
+ this.currentSpec = spec;
+
+ if (func) {
+ spec.runs(func);
+ }
+
+ return spec;
+};
+
+jasmine.Env.prototype.xit = function(desc, func) {
+ return {
+ id: this.nextSpecId(),
+ runs: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
+ if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
+ return true;
+ }
+
+ a.__Jasmine_been_here_before__ = b;
+ b.__Jasmine_been_here_before__ = a;
+
+ var hasKey = function(obj, keyName) {
+ return obj !== null && obj[keyName] !== jasmine.undefined;
+ };
+
+ for (var property in b) {
+ if (!hasKey(a, property) && hasKey(b, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ }
+ for (property in a) {
+ if (!hasKey(b, property) && hasKey(a, property)) {
+ mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
+ }
+ }
+ for (property in b) {
+ if (property == '__Jasmine_been_here_before__') continue;
+ if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
+ mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
+ }
+ }
+
+ if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
+ mismatchValues.push("arrays were not the same length");
+ }
+
+ delete a.__Jasmine_been_here_before__;
+ delete b.__Jasmine_been_here_before__;
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ for (var i = 0; i < this.equalityTesters_.length; i++) {
+ var equalityTester = this.equalityTesters_[i];
+ var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
+ if (result !== jasmine.undefined) return result;
+ }
+
+ if (a === b) return true;
+
+ if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
+ return (a == jasmine.undefined && b == jasmine.undefined);
+ }
+
+ if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
+ return a === b;
+ }
+
+ if (a instanceof Date && b instanceof Date) {
+ return a.getTime() == b.getTime();
+ }
+
+ if (a instanceof jasmine.Matchers.Any) {
+ return a.matches(b);
+ }
+
+ if (b instanceof jasmine.Matchers.Any) {
+ return b.matches(a);
+ }
+
+ if (jasmine.isString_(a) && jasmine.isString_(b)) {
+ return (a == b);
+ }
+
+ if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
+ return (a == b);
+ }
+
+ if (typeof a === "object" && typeof b === "object") {
+ return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
+ }
+
+ //Straight check
+ return (a === b);
+};
+
+jasmine.Env.prototype.contains_ = function(haystack, needle) {
+ if (jasmine.isArray_(haystack)) {
+ for (var i = 0; i < haystack.length; i++) {
+ if (this.equals_(haystack[i], needle)) return true;
+ }
+ return false;
+ }
+ return haystack.indexOf(needle) >= 0;
+};
+
+jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
+ this.equalityTesters_.push(equalityTester);
+};
+/** No-op base class for Jasmine reporters.
+ *
+ * @constructor
+ */
+jasmine.Reporter = function() {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecResults = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.log = function(str) {
+};
+
+/**
+ * Blocks are functions with executable code that make up a spec.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {Function} func
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Block = function(env, func, spec) {
+ this.env = env;
+ this.func = func;
+ this.spec = spec;
+};
+
+jasmine.Block.prototype.execute = function(onComplete) {
+ try {
+ this.func.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ }
+ onComplete();
+};
+/** JavaScript API reporter.
+ *
+ * @constructor
+ */
+jasmine.JsApiReporter = function() {
+ this.started = false;
+ this.finished = false;
+ this.suites_ = [];
+ this.results_ = {};
+};
+
+jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
+ this.started = true;
+ var suites = runner.topLevelSuites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ this.suites_.push(this.summarize_(suite));
+ }
+};
+
+jasmine.JsApiReporter.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
+ var isSuite = suiteOrSpec instanceof jasmine.Suite;
+ var summary = {
+ id: suiteOrSpec.id,
+ name: suiteOrSpec.description,
+ type: isSuite ? 'suite' : 'spec',
+ children: []
+ };
+
+ if (isSuite) {
+ var children = suiteOrSpec.children();
+ for (var i = 0; i < children.length; i++) {
+ summary.children.push(this.summarize_(children[i]));
+ }
+ }
+ return summary;
+};
+
+jasmine.JsApiReporter.prototype.results = function() {
+ return this.results_;
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
+ return this.results_[specId];
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
+ this.finished = true;
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
+ this.results_[spec.id] = {
+ messages: spec.results().getItems(),
+ result: spec.results().failedCount > 0 ? "failed" : "passed"
+ };
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.log = function(str) {
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
+ var results = {};
+ for (var i = 0; i < specIds.length; i++) {
+ var specId = specIds[i];
+ results[specId] = this.summarizeResult_(this.results_[specId]);
+ }
+ return results;
+};
+
+jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
+ var summaryMessages = [];
+ var messagesLength = result.messages.length;
+ for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
+ var resultMessage = result.messages[messageIndex];
+ summaryMessages.push({
+ text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
+ passed: resultMessage.passed ? resultMessage.passed() : true,
+ type: resultMessage.type,
+ message: resultMessage.message,
+ trace: {
+ stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
+ }
+ });
+ }
+
+ return {
+ result : result.result,
+ messages : summaryMessages
+ };
+};
+
+/**
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param actual
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Matchers = function(env, actual, spec, opt_isNot) {
+ this.env = env;
+ this.actual = actual;
+ this.spec = spec;
+ this.isNot = opt_isNot || false;
+ this.reportWasCalled_ = false;
+};
+
+// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
+jasmine.Matchers.pp = function(str) {
+ throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
+};
+
+// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
+jasmine.Matchers.prototype.report = function(result, failing_message, details) {
+ throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
+};
+
+jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
+ for (var methodName in prototype) {
+ if (methodName == 'report') continue;
+ var orig = prototype[methodName];
+ matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
+ }
+};
+
+jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
+ return function() {
+ var matcherArgs = jasmine.util.argsToArray(arguments);
+ var result = matcherFunction.apply(this, arguments);
+
+ if (this.isNot) {
+ result = !result;
+ }
+
+ if (this.reportWasCalled_) return result;
+
+ var message;
+ if (!result) {
+ if (this.message) {
+ message = this.message.apply(this, arguments);
+ if (jasmine.isArray_(message)) {
+ message = message[this.isNot ? 1 : 0];
+ }
+ } else {
+ var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+ message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
+ if (matcherArgs.length > 0) {
+ for (var i = 0; i < matcherArgs.length; i++) {
+ if (i > 0) message += ",";
+ message += " " + jasmine.pp(matcherArgs[i]);
+ }
+ }
+ message += ".";
+ }
+ }
+ var expectationResult = new jasmine.ExpectationResult({
+ matcherName: matcherName,
+ passed: result,
+ expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
+ actual: this.actual,
+ message: message
+ });
+ this.spec.addMatcherResult(expectationResult);
+ return jasmine.undefined;
+ };
+};
+
+
+
+
+/**
+ * toBe: compares the actual to the expected using ===
+ * @param expected
+ */
+jasmine.Matchers.prototype.toBe = function(expected) {
+ return this.actual === expected;
+};
+
+/**
+ * toNotBe: compares the actual to the expected using !==
+ * @param expected
+ * @deprecated as of 1.0. Use not.toBe() instead.
+ */
+jasmine.Matchers.prototype.toNotBe = function(expected) {
+ return this.actual !== expected;
+};
+
+/**
+ * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toEqual = function(expected) {
+ return this.env.equals_(this.actual, expected);
+};
+
+/**
+ * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
+ * @param expected
+ * @deprecated as of 1.0. Use not.toNotEqual() instead.
+ */
+jasmine.Matchers.prototype.toNotEqual = function(expected) {
+ return !this.env.equals_(this.actual, expected);
+};
+
+/**
+ * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
+ * a pattern or a String.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toMatch = function(expected) {
+ return new RegExp(expected).test(this.actual);
+};
+
+/**
+ * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
+ * @param expected
+ * @deprecated as of 1.0. Use not.toMatch() instead.
+ */
+jasmine.Matchers.prototype.toNotMatch = function(expected) {
+ return !(new RegExp(expected).test(this.actual));
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeDefined = function() {
+ return (this.actual !== jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeUndefined = function() {
+ return (this.actual === jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to null.
+ */
+jasmine.Matchers.prototype.toBeNull = function() {
+ return (this.actual === null);
+};
+
+/**
+ * Matcher that boolean not-nots the actual.
+ */
+jasmine.Matchers.prototype.toBeTruthy = function() {
+ return !!this.actual;
+};
+
+
+/**
+ * Matcher that boolean nots the actual.
+ */
+jasmine.Matchers.prototype.toBeFalsy = function() {
+ return !this.actual;
+};
+
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called.
+ */
+jasmine.Matchers.prototype.toHaveBeenCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to have been called.",
+ "Expected spy " + this.actual.identity + " not to have been called."
+ ];
+ };
+
+ return this.actual.wasCalled;
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
+jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was not called.
+ *
+ * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
+ */
+jasmine.Matchers.prototype.wasNotCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('wasNotCalled does not take arguments');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to not have been called.",
+ "Expected spy " + this.actual.identity + " to have been called."
+ ];
+ };
+
+ return !this.actual.wasCalled;
+};
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
+ *
+ * @example
+ *
+ */
+jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+ this.message = function() {
+ if (this.actual.callCount === 0) {
+ // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
+ return [
+ "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
+ "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
+ ];
+ } else {
+ return [
+ "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
+ "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
+ ];
+ }
+ };
+
+ return this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
+
+/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasNotCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
+ "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
+ ];
+ };
+
+ return !this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/**
+ * Matcher that checks that the expected item is an element in the actual Array.
+ *
+ * @param {Object} expected
+ */
+jasmine.Matchers.prototype.toContain = function(expected) {
+ return this.env.contains_(this.actual, expected);
+};
+
+/**
+ * Matcher that checks that the expected item is NOT an element in the actual Array.
+ *
+ * @param {Object} expected
+ * @deprecated as of 1.0. Use not.toNotContain() instead.
+ */
+jasmine.Matchers.prototype.toNotContain = function(expected) {
+ return !this.env.contains_(this.actual, expected);
+};
+
+jasmine.Matchers.prototype.toBeLessThan = function(expected) {
+ return this.actual < expected;
+};
+
+jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
+ return this.actual > expected;
+};
+
+/**
+ * Matcher that checks that the expected item is equal to the actual item
+ * up to a given level of decimal precision (default 2).
+ *
+ * @param {Number} expected
+ * @param {Number} precision
+ */
+jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
+ if (!(precision === 0)) {
+ precision = precision || 2;
+ }
+ var multiplier = Math.pow(10, precision);
+ var actual = Math.round(this.actual * multiplier);
+ expected = Math.round(expected * multiplier);
+ return expected == actual;
+};
+
+/**
+ * Matcher that checks that the expected exception was thrown by the actual.
+ *
+ * @param {String} expected
+ */
+jasmine.Matchers.prototype.toThrow = function(expected) {
+ var result = false;
+ var exception;
+ if (typeof this.actual != 'function') {
+ throw new Error('Actual is not a function');
+ }
+ try {
+ this.actual();
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
+ }
+
+ var not = this.isNot ? "not " : "";
+
+ this.message = function() {
+ if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
+ return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
+ } else {
+ return "Expected function to throw an exception.";
+ }
+ };
+
+ return result;
+};
+
+jasmine.Matchers.Any = function(expectedClass) {
+ this.expectedClass = expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.matches = function(other) {
+ if (this.expectedClass == String) {
+ return typeof other == 'string' || other instanceof String;
+ }
+
+ if (this.expectedClass == Number) {
+ return typeof other == 'number' || other instanceof Number;
+ }
+
+ if (this.expectedClass == Function) {
+ return typeof other == 'function' || other instanceof Function;
+ }
+
+ if (this.expectedClass == Object) {
+ return typeof other == 'object';
+ }
+
+ return other instanceof this.expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.toString = function() {
+ return '<jasmine.any(' + this.expectedClass + ')>';
+};
+
+/**
+ * @constructor
+ */
+jasmine.MultiReporter = function() {
+ this.subReporters_ = [];
+};
+jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
+
+jasmine.MultiReporter.prototype.addReporter = function(reporter) {
+ this.subReporters_.push(reporter);
+};
+
+(function() {
+ var functionNames = [
+ "reportRunnerStarting",
+ "reportRunnerResults",
+ "reportSuiteResults",
+ "reportSpecStarting",
+ "reportSpecResults",
+ "log"
+ ];
+ for (var i = 0; i < functionNames.length; i++) {
+ var functionName = functionNames[i];
+ jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
+ return function() {
+ for (var j = 0; j < this.subReporters_.length; j++) {
+ var subReporter = this.subReporters_[j];
+ if (subReporter[functionName]) {
+ subReporter[functionName].apply(subReporter, arguments);
+ }
+ }
+ };
+ })(functionName);
+ }
+})();
+/**
+ * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
+ *
+ * @constructor
+ */
+jasmine.NestedResults = function() {
+ /**
+ * The total count of results
+ */
+ this.totalCount = 0;
+ /**
+ * Number of passed results
+ */
+ this.passedCount = 0;
+ /**
+ * Number of failed results
+ */
+ this.failedCount = 0;
+ /**
+ * Was this suite/spec skipped?
+ */
+ this.skipped = false;
+ /**
+ * @ignore
+ */
+ this.items_ = [];
+};
+
+/**
+ * Roll up the result counts.
+ *
+ * @param result
+ */
+jasmine.NestedResults.prototype.rollupCounts = function(result) {
+ this.totalCount += result.totalCount;
+ this.passedCount += result.passedCount;
+ this.failedCount += result.failedCount;
+};
+
+/**
+ * Adds a log message.
+ * @param values Array of message parts which will be concatenated later.
+ */
+jasmine.NestedResults.prototype.log = function(values) {
+ this.items_.push(new jasmine.MessageResult(values));
+};
+
+/**
+ * Getter for the results: message & results.
+ */
+jasmine.NestedResults.prototype.getItems = function() {
+ return this.items_;
+};
+
+/**
+ * Adds a result, tracking counts (total, passed, & failed)
+ * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
+ */
+jasmine.NestedResults.prototype.addResult = function(result) {
+ if (result.type != 'log') {
+ if (result.items_) {
+ this.rollupCounts(result);
+ } else {
+ this.totalCount++;
+ if (result.passed()) {
+ this.passedCount++;
+ } else {
+ this.failedCount++;
+ }
+ }
+ }
+ this.items_.push(result);
+};
+
+/**
+ * @returns {Boolean} True if <b>everything</b> below passed
+ */
+jasmine.NestedResults.prototype.passed = function() {
+ return this.passedCount === this.totalCount;
+};
+/**
+ * Base class for pretty printing for expectation results.
+ */
+jasmine.PrettyPrinter = function() {
+ this.ppNestLevel_ = 0;
+};
+
+/**
+ * Formats a value in a nice, human-readable string.
+ *
+ * @param value
+ */
+jasmine.PrettyPrinter.prototype.format = function(value) {
+ if (this.ppNestLevel_ > 40) {
+ throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
+ }
+
+ this.ppNestLevel_++;
+ try {
+ if (value === jasmine.undefined) {
+ this.emitScalar('undefined');
+ } else if (value === null) {
+ this.emitScalar('null');
+ } else if (value === jasmine.getGlobal()) {
+ this.emitScalar('<global>');
+ } else if (value instanceof jasmine.Matchers.Any) {
+ this.emitScalar(value.toString());
+ } else if (typeof value === 'string') {
+ this.emitString(value);
+ } else if (jasmine.isSpy(value)) {
+ this.emitScalar("spy on " + value.identity);
+ } else if (value instanceof RegExp) {
+ this.emitScalar(value.toString());
+ } else if (typeof value === 'function') {
+ this.emitScalar('Function');
+ } else if (typeof value.nodeType === 'number') {
+ this.emitScalar('HTMLNode');
+ } else if (value instanceof Date) {
+ this.emitScalar('Date(' + value + ')');
+ } else if (value.__Jasmine_been_here_before__) {
+ this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
+ } else if (jasmine.isArray_(value) || typeof value == 'object') {
+ value.__Jasmine_been_here_before__ = true;
+ if (jasmine.isArray_(value)) {
+ this.emitArray(value);
+ } else {
+ this.emitObject(value);
+ }
+ delete value.__Jasmine_been_here_before__;
+ } else {
+ this.emitScalar(value.toString());
+ }
+ } finally {
+ this.ppNestLevel_--;
+ }
+};
+
+jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
+ for (var property in obj) {
+ if (property == '__Jasmine_been_here_before__') continue;
+ fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
+ obj.__lookupGetter__(property) !== null) : false);
+ }
+};
+
+jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
+
+jasmine.StringPrettyPrinter = function() {
+ jasmine.PrettyPrinter.call(this);
+
+ this.string = '';
+};
+jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
+
+jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
+ this.append(value);
+};
+
+jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
+ this.append("'" + value + "'");
+};
+
+jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
+ this.append('[ ');
+ for (var i = 0; i < array.length; i++) {
+ if (i > 0) {
+ this.append(', ');
+ }
+ this.format(array[i]);
+ }
+ this.append(' ]');
+};
+
+jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
+ var self = this;
+ this.append('{ ');
+ var first = true;
+
+ this.iterateObject(obj, function(property, isGetter) {
+ if (first) {
+ first = false;
+ } else {
+ self.append(', ');
+ }
+
+ self.append(property);
+ self.append(' : ');
+ if (isGetter) {
+ self.append('<getter>');
+ } else {
+ self.format(obj[property]);
+ }
+ });
+
+ this.append(' }');
+};
+
+jasmine.StringPrettyPrinter.prototype.append = function(value) {
+ this.string += value;
+};
+jasmine.Queue = function(env) {
+ this.env = env;
+ this.blocks = [];
+ this.running = false;
+ this.index = 0;
+ this.offset = 0;
+ this.abort = false;
+};
+
+jasmine.Queue.prototype.addBefore = function(block) {
+ this.blocks.unshift(block);
+};
+
+jasmine.Queue.prototype.add = function(block) {
+ this.blocks.push(block);
+};
+
+jasmine.Queue.prototype.insertNext = function(block) {
+ this.blocks.splice((this.index + this.offset + 1), 0, block);
+ this.offset++;
+};
+
+jasmine.Queue.prototype.start = function(onComplete) {
+ this.running = true;
+ this.onComplete = onComplete;
+ this.next_();
+};
+
+jasmine.Queue.prototype.isRunning = function() {
+ return this.running;
+};
+
+jasmine.Queue.LOOP_DONT_RECURSE = true;
+
+jasmine.Queue.prototype.next_ = function() {
+ var self = this;
+ var goAgain = true;
+
+ while (goAgain) {
+ goAgain = false;
+
+ if (self.index < self.blocks.length && !this.abort) {
+ var calledSynchronously = true;
+ var completedSynchronously = false;
+
+ var onComplete = function () {
+ if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
+ completedSynchronously = true;
+ return;
+ }
+
+ if (self.blocks[self.index].abort) {
+ self.abort = true;
+ }
+
+ self.offset = 0;
+ self.index++;
+
+ var now = new Date().getTime();
+ if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
+ self.env.lastUpdate = now;
+ self.env.setTimeout(function() {
+ self.next_();
+ }, 0);
+ } else {
+ if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
+ goAgain = true;
+ } else {
+ self.next_();
+ }
+ }
+ };
+ self.blocks[self.index].execute(onComplete);
+
+ calledSynchronously = false;
+ if (completedSynchronously) {
+ onComplete();
+ }
+
+ } else {
+ self.running = false;
+ if (self.onComplete) {
+ self.onComplete();
+ }
+ }
+ }
+};
+
+jasmine.Queue.prototype.results = function() {
+ var results = new jasmine.NestedResults();
+ for (var i = 0; i < this.blocks.length; i++) {
+ if (this.blocks[i].results) {
+ results.addResult(this.blocks[i].results());
+ }
+ }
+ return results;
+};
+
+
+/**
+ * Runner
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ */
+jasmine.Runner = function(env) {
+ var self = this;
+ self.env = env;
+ self.queue = new jasmine.Queue(env);
+ self.before_ = [];
+ self.after_ = [];
+ self.suites_ = [];
+};
+
+jasmine.Runner.prototype.execute = function() {
+ var self = this;
+ if (self.env.reporter.reportRunnerStarting) {
+ self.env.reporter.reportRunnerStarting(this);
+ }
+ self.queue.start(function () {
+ self.finishCallback();
+ });
+};
+
+jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.splice(0,0,beforeEachFunction);
+};
+
+jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.splice(0,0,afterEachFunction);
+};
+
+
+jasmine.Runner.prototype.finishCallback = function() {
+ this.env.reporter.reportRunnerResults(this);
+};
+
+jasmine.Runner.prototype.addSuite = function(suite) {
+ this.suites_.push(suite);
+};
+
+jasmine.Runner.prototype.add = function(block) {
+ if (block instanceof jasmine.Suite) {
+ this.addSuite(block);
+ }
+ this.queue.add(block);
+};
+
+jasmine.Runner.prototype.specs = function () {
+ var suites = this.suites();
+ var specs = [];
+ for (var i = 0; i < suites.length; i++) {
+ specs = specs.concat(suites[i].specs());
+ }
+ return specs;
+};
+
+jasmine.Runner.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Runner.prototype.topLevelSuites = function() {
+ var topLevelSuites = [];
+ for (var i = 0; i < this.suites_.length; i++) {
+ if (!this.suites_[i].parentSuite) {
+ topLevelSuites.push(this.suites_[i]);
+ }
+ }
+ return topLevelSuites;
+};
+
+jasmine.Runner.prototype.results = function() {
+ return this.queue.results();
+};
+/**
+ * Internal representation of a Jasmine specification, or test.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {jasmine.Suite} suite
+ * @param {String} description
+ */
+jasmine.Spec = function(env, suite, description) {
+ if (!env) {
+ throw new Error('jasmine.Env() required');
+ }
+ if (!suite) {
+ throw new Error('jasmine.Suite() required');
+ }
+ var spec = this;
+ spec.id = env.nextSpecId ? env.nextSpecId() : null;
+ spec.env = env;
+ spec.suite = suite;
+ spec.description = description;
+ spec.queue = new jasmine.Queue(env);
+
+ spec.afterCallbacks = [];
+ spec.spies_ = [];
+
+ spec.results_ = new jasmine.NestedResults();
+ spec.results_.description = description;
+ spec.matchersClass = null;
+};
+
+jasmine.Spec.prototype.getFullName = function() {
+ return this.suite.getFullName() + ' ' + this.description + '.';
+};
+
+
+jasmine.Spec.prototype.results = function() {
+ return this.results_;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the spec's output.
+ *
+ * Be careful not to leave calls to <code>jasmine.log</code> in production code.
+ */
+jasmine.Spec.prototype.log = function() {
+ return this.results_.log(arguments);
+};
+
+jasmine.Spec.prototype.runs = function (func) {
+ var block = new jasmine.Block(this.env, func, this);
+ this.addToQueue(block);
+ return this;
+};
+
+jasmine.Spec.prototype.addToQueue = function (block) {
+ if (this.queue.isRunning()) {
+ this.queue.insertNext(block);
+ } else {
+ this.queue.add(block);
+ }
+};
+
+/**
+ * @param {jasmine.ExpectationResult} result
+ */
+jasmine.Spec.prototype.addMatcherResult = function(result) {
+ this.results_.addResult(result);
+};
+
+jasmine.Spec.prototype.expect = function(actual) {
+ var positive = new (this.getMatchersClass_())(this.env, actual, this);
+ positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
+ return positive;
+};
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+jasmine.Spec.prototype.waits = function(timeout) {
+ var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
+ this.addToQueue(waitsFunc);
+ return this;
+};
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ var latchFunction_ = null;
+ var optional_timeoutMessage_ = null;
+ var optional_timeout_ = null;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var arg = arguments[i];
+ switch (typeof arg) {
+ case 'function':
+ latchFunction_ = arg;
+ break;
+ case 'string':
+ optional_timeoutMessage_ = arg;
+ break;
+ case 'number':
+ optional_timeout_ = arg;
+ break;
+ }
+ }
+
+ var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
+ this.addToQueue(waitsForFunc);
+ return this;
+};
+
+jasmine.Spec.prototype.fail = function (e) {
+ var expectationResult = new jasmine.ExpectationResult({
+ passed: false,
+ message: e ? jasmine.util.formatException(e) : 'Exception',
+ trace: { stack: e.stack }
+ });
+ this.results_.addResult(expectationResult);
+};
+
+jasmine.Spec.prototype.getMatchersClass_ = function() {
+ return this.matchersClass || this.env.matchersClass;
+};
+
+jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
+ var parent = this.getMatchersClass_();
+ var newMatchersClass = function() {
+ parent.apply(this, arguments);
+ };
+ jasmine.util.inherit(newMatchersClass, parent);
+ jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
+ this.matchersClass = newMatchersClass;
+};
+
+jasmine.Spec.prototype.finishCallback = function() {
+ this.env.reporter.reportSpecResults(this);
+};
+
+jasmine.Spec.prototype.finish = function(onComplete) {
+ this.removeAllSpies();
+ this.finishCallback();
+ if (onComplete) {
+ onComplete();
+ }
+};
+
+jasmine.Spec.prototype.after = function(doAfter) {
+ if (this.queue.isRunning()) {
+ this.queue.add(new jasmine.Block(this.env, doAfter, this));
+ } else {
+ this.afterCallbacks.unshift(doAfter);
+ }
+};
+
+jasmine.Spec.prototype.execute = function(onComplete) {
+ var spec = this;
+ if (!spec.env.specFilter(spec)) {
+ spec.results_.skipped = true;
+ spec.finish(onComplete);
+ return;
+ }
+
+ this.env.reporter.reportSpecStarting(this);
+
+ spec.env.currentSpec = spec;
+
+ spec.addBeforesAndAftersToQueue();
+
+ spec.queue.start(function () {
+ spec.finish(onComplete);
+ });
+};
+
+jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
+ var runner = this.env.currentRunner();
+ var i;
+
+ for (var suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
+ }
+ }
+ for (i = 0; i < runner.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
+ }
+ for (i = 0; i < this.afterCallbacks.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
+ }
+ for (suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
+ }
+ }
+ for (i = 0; i < runner.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
+ }
+};
+
+jasmine.Spec.prototype.explodes = function() {
+ throw 'explodes function should not have been called';
+};
+
+jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
+ if (obj == jasmine.undefined) {
+ throw "spyOn could not find an object to spy upon for " + methodName + "()";
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
+ throw methodName + '() method does not exist';
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
+ throw new Error(methodName + ' has already been spied upon');
+ }
+
+ var spyObj = jasmine.createSpy(methodName);
+
+ this.spies_.push(spyObj);
+ spyObj.baseObj = obj;
+ spyObj.methodName = methodName;
+ spyObj.originalValue = obj[methodName];
+
+ obj[methodName] = spyObj;
+
+ return spyObj;
+};
+
+jasmine.Spec.prototype.removeAllSpies = function() {
+ for (var i = 0; i < this.spies_.length; i++) {
+ var spy = this.spies_[i];
+ spy.baseObj[spy.methodName] = spy.originalValue;
+ }
+ this.spies_ = [];
+};
+
+/**
+ * Internal representation of a Jasmine suite.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {String} description
+ * @param {Function} specDefinitions
+ * @param {jasmine.Suite} parentSuite
+ */
+jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
+ var self = this;
+ self.id = env.nextSuiteId ? env.nextSuiteId() : null;
+ self.description = description;
+ self.queue = new jasmine.Queue(env);
+ self.parentSuite = parentSuite;
+ self.env = env;
+ self.before_ = [];
+ self.after_ = [];
+ self.children_ = [];
+ self.suites_ = [];
+ self.specs_ = [];
+};
+
+jasmine.Suite.prototype.getFullName = function() {
+ var fullName = this.description;
+ for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+ fullName = parentSuite.description + ' ' + fullName;
+ }
+ return fullName;
+};
+
+jasmine.Suite.prototype.finish = function(onComplete) {
+ this.env.reporter.reportSuiteResults(this);
+ this.finished = true;
+ if (typeof(onComplete) == 'function') {
+ onComplete();
+ }
+};
+
+jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.unshift(beforeEachFunction);
+};
+
+jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.unshift(afterEachFunction);
+};
+
+jasmine.Suite.prototype.results = function() {
+ return this.queue.results();
+};
+
+jasmine.Suite.prototype.add = function(suiteOrSpec) {
+ this.children_.push(suiteOrSpec);
+ if (suiteOrSpec instanceof jasmine.Suite) {
+ this.suites_.push(suiteOrSpec);
+ this.env.currentRunner().addSuite(suiteOrSpec);
+ } else {
+ this.specs_.push(suiteOrSpec);
+ }
+ this.queue.add(suiteOrSpec);
+};
+
+jasmine.Suite.prototype.specs = function() {
+ return this.specs_;
+};
+
+jasmine.Suite.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Suite.prototype.children = function() {
+ return this.children_;
+};
+
+jasmine.Suite.prototype.execute = function(onComplete) {
+ var self = this;
+ this.queue.start(function () {
+ self.finish(onComplete);
+ });
+};
+jasmine.WaitsBlock = function(env, timeout, spec) {
+ this.timeout = timeout;
+ jasmine.Block.call(this, env, null, spec);
+};
+
+jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
+
+jasmine.WaitsBlock.prototype.execute = function (onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
+ }
+ this.env.setTimeout(function () {
+ onComplete();
+ }, this.timeout);
+};
+/**
+ * A block which waits for some condition to become true, with timeout.
+ *
+ * @constructor
+ * @extends jasmine.Block
+ * @param {jasmine.Env} env The Jasmine environment.
+ * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
+ * @param {Function} latchFunction A function which returns true when the desired condition has been met.
+ * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
+ * @param {jasmine.Spec} spec The Jasmine spec.
+ */
+jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
+ this.timeout = timeout || env.defaultTimeoutInterval;
+ this.latchFunction = latchFunction;
+ this.message = message;
+ this.totalTimeSpentWaitingForLatch = 0;
+ jasmine.Block.call(this, env, null, spec);
+};
+jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
+
+jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
+
+jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
+ }
+ var latchFunctionResult;
+ try {
+ latchFunctionResult = this.latchFunction.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ onComplete();
+ return;
+ }
+
+ if (latchFunctionResult) {
+ onComplete();
+ } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
+ var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
+ this.spec.fail({
+ name: 'timeout',
+ message: message
+ });
+
+ this.abort = true;
+ onComplete();
+ } else {
+ this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
+ var self = this;
+ this.env.setTimeout(function() {
+ self.execute(onComplete);
+ }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
+ }
+};
+// Mock setTimeout, clearTimeout
+// Contributed by Pivotal Computer Systems, www.pivotalsf.com
+
+jasmine.FakeTimer = function() {
+ this.reset();
+
+ var self = this;
+ self.setTimeout = function(funcToCall, millis) {
+ self.timeoutsMade++;
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
+ return self.timeoutsMade;
+ };
+
+ self.setInterval = function(funcToCall, millis) {
+ self.timeoutsMade++;
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
+ return self.timeoutsMade;
+ };
+
+ self.clearTimeout = function(timeoutKey) {
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ };
+
+ self.clearInterval = function(timeoutKey) {
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ };
+
+};
+
+jasmine.FakeTimer.prototype.reset = function() {
+ this.timeoutsMade = 0;
+ this.scheduledFunctions = {};
+ this.nowMillis = 0;
+};
+
+jasmine.FakeTimer.prototype.tick = function(millis) {
+ var oldMillis = this.nowMillis;
+ var newMillis = oldMillis + millis;
+ this.runFunctionsWithinRange(oldMillis, newMillis);
+ this.nowMillis = newMillis;
+};
+
+jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
+ var scheduledFunc;
+ var funcsToRun = [];
+ for (var timeoutKey in this.scheduledFunctions) {
+ scheduledFunc = this.scheduledFunctions[timeoutKey];
+ if (scheduledFunc != jasmine.undefined &&
+ scheduledFunc.runAtMillis >= oldMillis &&
+ scheduledFunc.runAtMillis <= nowMillis) {
+ funcsToRun.push(scheduledFunc);
+ this.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ }
+ }
+
+ if (funcsToRun.length > 0) {
+ funcsToRun.sort(function(a, b) {
+ return a.runAtMillis - b.runAtMillis;
+ });
+ for (var i = 0; i < funcsToRun.length; ++i) {
+ try {
+ var funcToRun = funcsToRun[i];
+ this.nowMillis = funcToRun.runAtMillis;
+ funcToRun.funcToCall();
+ if (funcToRun.recurring) {
+ this.scheduleFunction(funcToRun.timeoutKey,
+ funcToRun.funcToCall,
+ funcToRun.millis,
+ true);
+ }
+ } catch(e) {
+ }
+ }
+ this.runFunctionsWithinRange(oldMillis, nowMillis);
+ }
+};
+
+jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
+ this.scheduledFunctions[timeoutKey] = {
+ runAtMillis: this.nowMillis + millis,
+ funcToCall: funcToCall,
+ recurring: recurring,
+ timeoutKey: timeoutKey,
+ millis: millis
+ };
+};
+
+/**
+ * @namespace
+ */
+jasmine.Clock = {
+ defaultFakeTimer: new jasmine.FakeTimer(),
+
+ reset: function() {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.defaultFakeTimer.reset();
+ },
+
+ tick: function(millis) {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.defaultFakeTimer.tick(millis);
+ },
+
+ runFunctionsWithinRange: function(oldMillis, nowMillis) {
+ jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
+ },
+
+ scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
+ jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
+ },
+
+ useMock: function() {
+ if (!jasmine.Clock.isInstalled()) {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.after(jasmine.Clock.uninstallMock);
+
+ jasmine.Clock.installMock();
+ }
+ },
+
+ installMock: function() {
+ jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
+ },
+
+ uninstallMock: function() {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.installed = jasmine.Clock.real;
+ },
+
+ real: {
+ setTimeout: jasmine.getGlobal().setTimeout,
+ clearTimeout: jasmine.getGlobal().clearTimeout,
+ setInterval: jasmine.getGlobal().setInterval,
+ clearInterval: jasmine.getGlobal().clearInterval
+ },
+
+ assertInstalled: function() {
+ if (!jasmine.Clock.isInstalled()) {
+ throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
+ }
+ },
+
+ isInstalled: function() {
+ return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
+ },
+
+ installed: null
+};
+jasmine.Clock.installed = jasmine.Clock.real;
+
+//else for IE support
+jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
+ if (jasmine.Clock.installed.setTimeout.apply) {
+ return jasmine.Clock.installed.setTimeout.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.setTimeout(funcToCall, millis);
+ }
+};
+
+jasmine.getGlobal().setInterval = function(funcToCall, millis) {
+ if (jasmine.Clock.installed.setInterval.apply) {
+ return jasmine.Clock.installed.setInterval.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.setInterval(funcToCall, millis);
+ }
+};
+
+jasmine.getGlobal().clearTimeout = function(timeoutKey) {
+ if (jasmine.Clock.installed.clearTimeout.apply) {
+ return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.clearTimeout(timeoutKey);
+ }
+};
+
+jasmine.getGlobal().clearInterval = function(timeoutKey) {
+ if (jasmine.Clock.installed.clearTimeout.apply) {
+ return jasmine.Clock.installed.clearInterval.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.clearInterval(timeoutKey);
+ }
+};
+
+jasmine.version_= {
+ "major": 1,
+ "minor": 1,
+ "build": 0,
+ "revision": 1308965645,
+ "release_candidate": 2
+};
diff --git a/doc/backends/deckjs/deck.js/test/settings.js b/doc/backends/deckjs/deck.js/test/settings.js
new file mode 100755
index 00000000..7ba223d5
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/settings.js
@@ -0,0 +1,3 @@
+// SETTINGS, VARS, UTILITY FUNCTIONS
+jasmine.getFixtures().fixturesPath = 'fixtures';
+var defaults = $.deck.defaults;
diff --git a/doc/backends/deckjs/deck.js/test/spec.core.js b/doc/backends/deckjs/deck.js/test/spec.core.js
new file mode 100755
index 00000000..cec71413
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/spec.core.js
@@ -0,0 +1,527 @@
+// Go tests, go
+describe('Deck JS', function() {
+ describe('standard html structure', function() {
+ beforeEach(function() {
+ loadFixtures('standard.html');
+ if (Modernizr.history) {
+ history.replaceState({}, "", "#")
+ }
+ else {
+ window.location.hash = '#';
+ }
+ });
+
+ describe('init(options.selectors.slides)', function() {
+ it('should create slides', function() {
+ $.deck({
+ selectors: {
+ slides: '.slide3'
+ }
+ });
+ expect($.deck('getSlides').length).toEqual($('.slide3').length);
+ });
+ });
+
+ describe('init(selector)', function() {
+ it('should create slides', function() {
+ $.deck();
+ expect($.deck('getSlides').length).toEqual($('.slide').length);
+ });
+ });
+
+ describe('init([selectors])', function() {
+ it('should create slides', function() {
+ $.deck([
+ '.slide1',
+ '.slide2',
+ '.slide3',
+ '.slide4',
+ '.slide5'
+ ]);
+ expect($.deck('getSlides').length).toEqual($('.slide').length);
+ });
+ });
+
+ describe('navigation functions', function() {
+ beforeEach(function() {
+ $.deck();
+ });
+
+ describe('go(i)', function() {
+ it('should go to the i slide (0 based index)', function() {
+ $.deck('go', 3);
+ expect($.deck('getSlide')).toHaveClass('slide4');
+ });
+
+ it('should go to the slide with specified id', function() {
+ $.deck('go', 'custom-id');
+ expect($.deck('getSlide')).toHaveId('custom-id');
+ });
+
+ it('should go nowhere if i is out of bounds', function() {
+ $.deck('go', 5);
+ expect($.deck('getSlide')).toHaveClass('slide1');
+ });
+
+ it('should go nowhere if id does not exist', function() {
+ $.deck('go', 'i-dont-exist');
+ expect($.deck('getSlide')).toHaveClass('slide1');
+ });
+
+ describe('aria attribute updates', function() {
+ beforeEach(function() {
+ loadFixtures('nesteds.html');
+ $.deck();
+ $.deck('go', 5);
+ });
+
+ it('should set offscreen slides to hidden true', function() {
+ $([
+ '.toplevel.deck-before:not(.deck-child-current)',
+ '.toplevel.deck-previous:not(.deck-child-current)',
+ '.deck-next',
+ '.deck-after'
+ ].join(', ')).each(function() {
+ expect($(this)).toHaveAttr('aria-hidden', 'true');
+ });
+ });
+
+ it('should set onscreen slides to hidden false', function() {
+ $([
+ '.deck-child-current.slide',
+ '.deck-child-current .deck-before',
+ '.deck-child-current .deck-previous',
+ '.deck-current'
+ ].join(', ')).each(function() {
+ expect($(this)).toHaveAttr('aria-hidden', 'false');
+ });
+ });
+ });
+ });
+
+ describe('next()', function() {
+ it('should go to the next slide', function() {
+ $.deck('next');
+ expect($.deck('getSlide')).toHaveClass('slide2');
+ });
+
+ it('should go nowhere if on the last slide', function() {
+ $.deck('go', 4);
+ $.deck('next');
+ expect($.deck('getSlide')).toHaveClass('slide5');
+ });
+ });
+
+ describe('prev()', function() {
+ it('should go to the previous slide', function() {
+ $.deck('go', 2);
+ $.deck('prev');
+ expect($.deck('getSlide')).toHaveClass('slide2');
+ });
+
+ it('should go nowhere if on the first slide', function() {
+ $.deck('prev');
+ expect($.deck('getSlide')).toHaveClass('slide1');
+ });
+ });
+ });
+
+ describe('getters', function() {
+ beforeEach(function() {
+ $.deck();
+ });
+
+ describe('getSlide()', function() {
+ it('should get the current slide', function() {
+ expect($.deck('getSlide')).toHaveClass('slide1');
+ $.deck('go', 2);
+ expect($.deck('getSlide')).toHaveClass('slide3');
+ });
+ });
+
+ describe('getSlide(i)', function() {
+ it('should get slide number i (0 based index)', function() {
+ expect($.deck('getSlide', 1)).toHaveClass('slide2');
+ expect($.deck('getSlide', 3)).toHaveClass('slide4');
+ });
+
+ it('should return null if i is NaN', function() {
+ expect($.deck('getSlide', 'barfoo')).toBeNull();
+ });
+
+ it('should return null if i is out of bounds', function() {
+ expect($.deck('getSlide', 6)).toBeNull();
+ });
+ });
+
+ describe('getSlides()', function() {
+ it('should return an array of jQuery objects for each slide', function() {
+ var expectation = [];
+ var slides = $.deck('getSlides');
+ $('.slide').each(function() {
+ expectation.push($(this));
+ });
+ expect(slides).toEqual(expectation);
+ });
+ });
+
+ describe('getContainer()', function() {
+ it('should return a jQuery object with the container element(s)', function() {
+ expect($.deck('getContainer')).toBe(defaults.selectors.container);
+ });
+ });
+
+ describe('getOptions()', function() {
+ it('should return the current options object', function() {
+ expect($.deck('getOptions')).toEqual(defaults);
+ });
+ });
+
+ describe('getTopLevelSlides()', function() {
+ it('should return only root slides', function() {
+ loadFixtures('nesteds.html');
+ $.deck();
+ var expectation = [];
+ var topLevelSlides = $.deck('getTopLevelSlides');
+ $('.toplevel').each(function() {
+ expectation.push($(this));
+ });
+ expect(topLevelSlides).toEqual(expectation);
+ });
+ });
+
+ describe('getNestedSlides()', function() {
+ it('should return nested slides for current slide', function() {
+ loadFixtures('nesteds.html');
+ $.deck();
+ $.deck('go', 2);
+ var expectation = [];
+ var nestedSlides = $.deck('getNestedSlides');
+ $.deck('getSlide').find('.slide').each(function() {
+ expectation.push($(this));
+ });
+ expect(nestedSlides).toEqual(expectation);
+ });
+ });
+ });
+
+ describe('container states', function() {
+ beforeEach(function() {
+ $.deck();
+ });
+
+ it('should start at state 0', function() {
+ expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '0');
+ });
+
+ it('should change states with the slide number', function() {
+ $.deck('next');
+ expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '1');
+ $.deck('go', 3);
+ expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '3');
+ $.deck('prev');
+ expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '2');
+ });
+ });
+
+ describe('options object', function() {
+ var $d = $(document);
+
+ beforeEach(function() {
+ $.deck('.alt-slide', {
+ classes: {
+ after: 'alt-after',
+ before: 'alt-before',
+ current: 'alt-current',
+ onPrefix: 'alt-on-',
+ next: 'alt-next',
+ previous: 'alt-prev'
+ },
+
+ selectors: {
+ container: '.alt-container'
+ },
+
+ keys: {
+ next: 87,
+ previous: 69
+ }
+ });
+ });
+
+ describe('classes', function() {
+ it('should use the specified after class', function() {
+ expect($('.alt-slide3, .alt-slide4, .alt-slide5')).toHaveClass('alt-after');
+ });
+
+ it('should use the specified before class', function() {
+ $.deck('go', 4);
+ expect($('.alt-slide1, .alt-slide2, .alt-slide3')).toHaveClass('alt-before');
+ });
+
+ it('should use the specified container class', function() {
+ $.deck('go', 2);
+ expect($('.alt-container')).toHaveClass('alt-on-2');
+ });
+
+ it('should use the specified current class', function() {
+ expect($.deck('getSlide')).toHaveClass('alt-current');
+ });
+
+ it('should use the specified next class', function() {
+ expect($('.alt-slide2')).toHaveClass('alt-next');
+ });
+
+ it('should use the specified previous class', function() {
+ $.deck('next');
+ expect($('.alt-slide1')).toHaveClass('alt-prev');
+ });
+ });
+
+ describe('key bindings', function() {
+ var e;
+
+ beforeEach(function() {
+ e = jQuery.Event('keydown.deck');
+ });
+
+ it('should go to the next slide using the specified key', function() {
+ e.which = 87; // 'w'
+ $d.trigger(e);
+ expect($.deck('getSlide')).toHaveClass('alt-slide2');
+ });
+
+ it('should go to the previous slide using the specified key', function() {
+ $.deck('next');
+ e.which = 69; // 'e'
+ $d.trigger(e);
+ expect($.deck('getSlide')).toHaveClass('alt-slide1');
+ });
+
+ it('should not trigger events that originate within editable elements', function() {
+ var $outside = $('<input type="text" />').appendTo('body');
+ e = jQuery.Event('keydown');
+ e.which = 87;
+ $outside.trigger(e);
+ expect($.deck('getSlide')).toHaveClass('alt-slide1');
+ $outside.remove();
+ });
+ });
+ });
+
+ describe('events', function() {
+ var $d;
+
+ beforeEach(function() {
+ $d = $(document);
+ });
+
+ describe('deck.change', function() {
+ var index, oldIndex;
+
+ beforeEach(function() {
+ $.deck();
+ $.deck('go', 1);
+ $d.one('deck.change', function(event, from, to) {
+ index = to;
+ oldIndex = from;
+ });
+ });
+
+ it('should fire on go(i)', function() {
+ $.deck('go', 3);
+ expect(index).toEqual(3);
+ });
+
+ it('should fire on next()', function() {
+ $.deck('next');
+ expect(index).toEqual(2);
+ });
+
+ it('should fire on prev()', function() {
+ $.deck('prev');
+ expect(index).toEqual(0);
+ });
+
+ it('should pass parameters with from and to indices', function() {
+ $.deck('go', 3);
+ expect(index).toEqual(3);
+ expect(oldIndex).toEqual(1);
+ });
+
+ it('should not fire if default prevented in beforeChange', function() {
+ $d.bind('deck.beforeChange', false);
+ $.deck('go', 3);
+ expect($.deck('getSlide')).toEqual($.deck('getSlide', 1));
+ $d.unbind('deck.beforeChange', false);
+ });
+ });
+
+ describe('deck.init', function() {
+ it('should fire on deck initialization', function() {
+ $.deck();
+ expect($.deck('getSlides').length).toBeGreaterThan(0);
+ });
+ });
+
+ describe('deck.beforeInit', function() {
+ var beforeHit;
+
+ beforeEach(function() {
+ beforeHit = false;
+ $d.on('deck.beforeInit', function() {
+ beforeHit = true;
+ });
+ });
+
+ it('should fire on deck initialization', function() {
+ $.deck();
+ expect(beforeHit).toBeTruthy();
+ });
+
+ it('should have populated the slides array', function() {
+ var f = function() {
+ expect($.deck('getSlides').length).toEqual($('.slide').length);
+ };
+
+ $d.bind('deck.beforeInit', f);
+ $.deck();
+ $d.unbind('deck.beforeInit', f);
+ });
+
+ it('should prevent the init event if lockInit is called', function() {
+ var initHit = false;
+ var f = function(event) {
+ event.lockInit();
+ };
+ var g = function() {
+ initHit = true;
+ };
+
+ $d.bind('deck.beforeInit', f);
+ $d.bind('deck.init', g);
+ $.deck();
+ $d.unbind('deck.beforeInit', f);
+ $d.unbind('deck.init', g);
+ expect(initHit).toBeFalsy();
+ });
+
+ it('should warn if locked without release', function() {
+ var warned = false;
+ var f = function(event) {
+ event.lockInit();
+ };
+ var warn = console.warn;
+ window.console.warn = function() {
+ warned = true;
+ };
+
+ $d.bind('deck.beforeInit', f);
+ $.deck('.slide', {
+ initLockTimeout: 20
+ });
+ $d.unbind('deck.beforeInit', f);
+
+ waitsFor(function() {
+ return warned;
+ }, 'warning', 2000);
+
+ runs(function() {
+ window.console.warn = warn;
+ });
+ });
+
+ it('should fire init event once releaseInit is called', function() {
+ var f = function(event) {
+ event.lockInit();
+ window.setTimeout(function() {
+ event.releaseInit();
+ }, 20);
+ };
+
+ runs(function() {
+ $d.bind('deck.beforeInit', f);
+ $.deck();
+ $d.unbind('deck.beforeInit', f);
+ });
+
+ waitsFor(function() {
+ return $.deck('getSlides').length > 0;
+ }, 'lock to release', 2000);
+ });
+ });
+ });
+
+ describe('hash/id assignments', function() {
+ beforeEach(function() {
+ $.deck('.slide');
+ });
+
+ it('should assign ids to slides that do not have them', function() {
+ var slides = $.deck('getSlides');
+ $.each(slides, function(i, $e) {
+ expect($e.attr('id')).toBeTruthy();
+ });
+ });
+
+ it('should reassign ids on reinitialization', function() {
+ var $firstSlide = $.deck('getSlide', 0);
+ var firstID = $firstSlide.attr('id');
+
+ $firstSlide.before('<div class="slide"></div>');
+ $.deck('.slide');
+ expect($firstSlide).not.toHaveId(firstID);
+ });
+
+ it('should update container with a state class including the slide id', function() {
+ var $c = $.deck('getContainer');
+ var osp = defaults.classes.onPrefix;
+
+ expect($c).toHaveClass(osp + $.deck('getSlide', 0).attr('id'));
+ $.deck('next');
+ expect($c).toHaveClass(osp + $.deck('getSlide', 1).attr('id'));
+ $.deck('next');
+ expect($c).not.toHaveClass(osp + $.deck('getSlide', 1).attr('id'));
+ expect($c).toHaveClass(osp + $.deck('getSlide', 2).attr('id'));
+ });
+
+ it('should use existing ids if they exist', function() {
+ expect($('#custom-id')).toExist();
+ });
+
+ it('should update the URL on slide change (if supported)', function() {
+ if (Modernizr.history) {
+ $.deck('go', 3);
+ expect(window.location.hash).toEqual('#slide-3');
+ }
+ });
+
+ it('should deep link to slide on deck init', function() {
+ window.location.hash = "#slide-3";
+ $.deck('.slide');
+ waitsFor(function() {
+ return $.deck('getSlide').attr('id') === 'slide-3';
+ });
+ });
+
+ it('should follow internal hash links using hashchange (if supported)', function() {
+ window.location.hash = "#slide-3";
+ // Hashchange event doesn't fire right when the hash changes?
+ waitsFor(function() {
+ return $.deck('getSlide').attr('id') === 'slide-3';
+ }, 'hash to change to slide-3', 2000);
+ });
+ });
+ });
+
+ describe('empty deck', function() {
+ beforeEach(function() {
+ loadFixtures('empty.html');
+ $.deck();
+ });
+
+ describe('getSlide()', function() {
+ it('should not error on init', $.noop);
+ });
+ });
+});
diff --git a/doc/backends/deckjs/deck.js/test/spec.goto.js b/doc/backends/deckjs/deck.js/test/spec.goto.js
new file mode 100644
index 00000000..014f3fa2
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/spec.goto.js
@@ -0,0 +1,154 @@
+describe('Deck JS Quick Go-To', function() {
+ var $d = $(document);
+
+ beforeEach(function() {
+ loadFixtures('standard.html');
+ if (Modernizr.history) {
+ history.replaceState({}, "", "#")
+ }
+ else {
+ window.location.hash = '#';
+ }
+ $.deck('.slide');
+ });
+
+ describe('showGoTo()', function() {
+ it('should show the go-to helper', function() {
+ expect($(defaults.selectors.container)).not.toHaveClass(defaults.classes.goto);
+ $.deck('showGoTo');
+ expect($(defaults.selectors.container)).toHaveClass(defaults.classes.goto);
+ });
+
+ it('should focus the go-to input', function() {
+ $.deck('showGoTo');
+ expect($(defaults.selectors.gotoInput)[0]).toEqual(document.activeElement);
+ });
+
+ it('should set aria-hidden to false', function() {
+ var $gotoForm = $(defaults.selectors.gotoForm);
+ $.deck('showGoTo');
+ expect($gotoForm).toHaveAttr('aria-hidden', 'false');
+ });
+ });
+
+ describe('hideGoTo()', function() {
+ beforeEach(function() {
+ $.deck('showGoTo');
+ $.deck('hideGoTo');
+ });
+
+ it('should hide the go-to helper', function() {
+ expect($(defaults.selectors.container)).not.toHaveClass(defaults.classes.goto);
+ });
+
+ it('should blur the go-to input', function() {
+ expect($(defaults.selectors.gotoInput)[0]).not.toEqual(document.activeElement);
+ });
+
+ it('should set aria-hidden to true', function() {
+ var $gotoForm = $(defaults.selectors.gotoForm);
+ $.deck('hideGoTo');
+ expect($gotoForm).toHaveAttr('aria-hidden', 'true');
+ });
+ });
+
+ describe('toggleGoTo()', function() {
+ it('should toggle the go-to helper on and off', function() {
+ expect($(defaults.selectors.container)).not.toHaveClass(defaults.classes.goto);
+ $.deck('toggleGoTo');
+ expect($(defaults.selectors.container)).toHaveClass(defaults.classes.goto);
+ $.deck('toggleGoTo');
+ expect($(defaults.selectors.container)).not.toHaveClass(defaults.classes.goto);
+ });
+ });
+
+ describe('Go-To submit', function() {
+ beforeEach(function() {
+ $.deck('showGoTo');
+ });
+
+ it('should hide the go-to helper', function() {
+ $(defaults.selectors.gotoInput).val('3');
+ $(defaults.selectors.gotoForm).submit();
+ expect($(defaults.selectors.container)).not.toHaveClass(defaults.classes.goto);
+ });
+
+ it('should go to the slide number entered', function() {
+ $(defaults.selectors.gotoInput).val('3');
+ $(defaults.selectors.gotoForm).submit();
+ expect($.deck('getSlide')).toEqual($.deck('getSlide'), 2);
+ });
+
+ it('should go to the slide id entered', function() {
+ $(defaults.selectors.gotoInput).val('custom-id');
+ $(defaults.selectors.gotoForm).submit();
+ expect($.deck('getSlide')).toEqual($.deck('getSlide'), 1);
+ });
+
+ it('should go nowhere if the number is negative', function() {
+ $(defaults.selectors.gotoInput).val('-2');
+ $(defaults.selectors.gotoForm).submit();
+ expect($.deck('getSlide')).toEqual($.deck('getSlide'), 0);
+ });
+
+ it('should go nowhere if the number is greater than the number of slides', function() {
+ $(defaults.selectors.gotoInput).val('9');
+ $(defaults.selectors.gotoForm).submit();
+ expect($.deck('getSlide')).toEqual($.deck('getSlide'), 0);
+ });
+
+ it('should go nowhere if the id does not exist', function() {
+ $(defaults.selectors.gotoInput).val('do-not-exist');
+ $(defaults.selectors.gotoForm).submit();
+ expect($.deck('getSlide')).toEqual($.deck('getSlide'), 0);
+ });
+ });
+
+ describe('Datalist population', function() {
+ it('should fill in options with all the slide ids', function() {
+ var $dataOptions = $(defaults.selectors.gotoDatalist).find('option');
+ expect($dataOptions.length).toEqual(5);
+ expect($dataOptions.eq(0).attr('value')).toEqual('slide-0');
+ expect($dataOptions.eq(1).attr('value')).toEqual('custom-id');
+ });
+ });
+
+ describe('key bindings', function() {
+ var e;
+
+ beforeEach(function() {
+ e = jQuery.Event('keydown.deckgoto');
+ });
+
+ it('should toggle the go-to helper if the specified key is pressed', function() {
+ e.which = 71; // g
+ $d.trigger(e);
+ expect($(defaults.selectors.container)).toHaveClass(defaults.classes.goto);
+ $d.trigger(e);
+ expect($(defaults.selectors.container)).not.toHaveClass(defaults.classes.goto);
+ });
+ });
+
+ describe('countNested false', function() {
+ beforeEach(function() {
+ loadFixtures('nesteds.html');
+ $.deck('.slide', {
+ countNested: false
+ });
+ $.deck('showGoTo');
+ });
+
+ it('should ignore nested slides when given a slide number', function() {
+ $(defaults.selectors.gotoInput).val('4');
+ $(defaults.selectors.gotoForm).submit();
+ expect($.deck('getSlide')).toHaveId('after');
+ });
+
+ it('should respect top side of new slide range', function() {
+ $.deck('go', 0);
+ $(defaults.selectors.gotoInput).val('6');
+ $(defaults.selectors.gotoForm).submit();
+ expect($.deck('getSlide')).toHaveId('slide-0');
+ });
+ });
+});
diff --git a/doc/backends/deckjs/deck.js/test/spec.menu.js b/doc/backends/deckjs/deck.js/test/spec.menu.js
new file mode 100644
index 00000000..3abca9fc
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/spec.menu.js
@@ -0,0 +1,83 @@
+describe('Deck JS Menu', function() {
+ var $d = $(document);
+ var dsc = defaults.selectors.container;
+
+ beforeEach(function() {
+ loadFixtures('standard.html');
+ if (Modernizr.history) {
+ history.replaceState({}, "", "#")
+ }
+ else {
+ window.location.hash = '#';
+ }
+ $.deck('.slide');
+ });
+
+ describe('showMenu()', function() {
+ it('should show the menu', function() {
+ expect($(dsc)).not.toHaveClass(defaults.classes.menu);
+ $.deck('showMenu');
+ expect($(dsc)).toHaveClass(defaults.classes.menu);
+ });
+
+ it('should do nothing if menu is already showing', function() {
+ if (Modernizr.csstransforms) {
+ $.deck('showMenu');
+ $.deck('showMenu');
+ $.deck('hideMenu');
+ expect($('.slide').attr('style')).toBeFalsy();
+ }
+ });
+ });
+
+ describe('hideMenu()', function() {
+ it('should hide the menu', function() {
+ $.deck('showMenu');
+ $.deck('hideMenu');
+ expect($(dsc)).not.toHaveClass(defaults.classes.menu);
+ });
+ });
+
+ describe('toggleMenu()', function() {
+ it('should toggle menu on and off', function() {
+ expect($(dsc)).not.toHaveClass(defaults.classes.menu);
+ $.deck('toggleMenu');
+ expect($(dsc)).toHaveClass(defaults.classes.menu);
+ $.deck('toggleMenu');
+ expect($(dsc)).not.toHaveClass(defaults.classes.menu);
+ });
+ });
+
+ describe('key bindings', function() {
+ var e;
+
+ beforeEach(function() {
+ e = jQuery.Event('keydown.deckmenu');
+ });
+
+ it('should toggle the menu if the specified key is pressed', function() {
+ e.which = 77; // m
+ $d.trigger(e);
+ expect($(dsc)).toHaveClass(defaults.classes.menu);
+ $d.trigger(e);
+ expect($(dsc)).not.toHaveClass(defaults.classes.menu);
+ });
+ });
+
+ describe('touch bindings', function() {
+ var estart, eend;
+
+ beforeEach(function() {
+ estart = jQuery.Event('touchstart.deckmenu');
+ eend = jQuery.Event('touchend.deckmenu');
+ });
+
+ it('should toggle the menu if the screen is touched', function() {
+ $.deck('getOptions').touch.doubletapWindow = Date.now() + 100000;
+ $.deck('getContainer').trigger(estart);
+ $.deck('getContainer').trigger(eend);
+ expect($(dsc)).toHaveClass(defaults.classes.menu);
+ });
+ });
+
+});
diff --git a/doc/backends/deckjs/deck.js/test/spec.navigation.js b/doc/backends/deckjs/deck.js/test/spec.navigation.js
new file mode 100644
index 00000000..db04794a
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/spec.navigation.js
@@ -0,0 +1,63 @@
+describe('Deck JS Navigation Buttons', function() {
+ beforeEach(function() {
+ loadFixtures('standard.html');
+ if (Modernizr.history) {
+ history.replaceState({}, "", "#")
+ }
+ else {
+ window.location.hash = '#';
+ }
+ $.deck('.slide');
+ });
+
+ it('should go to the next slide if next link is clicked', function() {
+ $(defaults.selectors.nextLink).click();
+ expect($.deck('getSlide')).toHaveClass('slide2');
+ });
+
+ it('should go to the previous slide if previous link is clicked', function() {
+ $.deck('go', 2);
+ $(defaults.selectors.previousLink).click();
+ expect($.deck('getSlide')).toHaveClass('slide2');
+ });
+
+ it('should add the disabled class to the previous link if on first slide', function() {
+ expect($(defaults.selectors.previousLink)).toHaveClass(defaults.classes.navDisabled);
+ $(defaults.selectors.nextLink).click();
+ expect($(defaults.selectors.previousLink)).not.toHaveClass(defaults.classes.navDisabled);
+ $(defaults.selectors.previousLink).click();
+ expect($(defaults.selectors.previousLink)).toHaveClass(defaults.classes.navDisabled);
+ });
+
+ it('should add aria-disabled to previous link if on first slide', function() {
+ $.deck('go', 0);
+ expect($(defaults.selectors.previousLink)).toHaveAttr('aria-disabled', 'true');
+ });
+
+ it('should add the disabled class to the next link if on last slide', function() {
+ expect($(defaults.selectors.nextLink)).not.toHaveClass(defaults.classes.navDisabled);
+ $.deck('go', $.deck('getSlides').length - 1);
+ expect($(defaults.selectors.nextLink)).toHaveClass(defaults.classes.navDisabled);
+ });
+
+ it('should add aria-disabled to next link if on last slide', function() {
+ $.deck('go', $.deck('getSlides').length - 1);
+ expect($(defaults.selectors.nextLink)).toHaveAttr('aria-disabled', 'true');
+ });
+
+ it('should not start disabled if deck initialized in the middle', function() {
+ $.deck('go', 2);
+ $.deck('.slide');
+ waitsFor(function() {
+ return !$(defaults.selectors.previousLink).hasClass(defaults.classes.navDisabled);
+ });
+ });
+
+ it('should update the links hrefs with real fragment ids', function() {
+ expect($(defaults.selectors.previousLink).attr('href')).toMatch(/#$/);
+ expect($(defaults.selectors.nextLink).attr('href')).toMatch('#custom-id');
+ $.deck('go', 2);
+ expect($(defaults.selectors.previousLink).attr('href')).toMatch('#custom-id');
+ expect($(defaults.selectors.nextLink).attr('href')).toMatch('#slide-3');
+ });
+});
diff --git a/doc/backends/deckjs/deck.js/test/spec.scale.js b/doc/backends/deckjs/deck.js/test/spec.scale.js
new file mode 100644
index 00000000..02be2d87
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/spec.scale.js
@@ -0,0 +1,57 @@
+describe('Deck JS Status Indicator', function() {
+ beforeEach(function() {
+ loadFixtures('standard.html');
+ if (Modernizr.history) {
+ history.replaceState({}, "", "#")
+ }
+ else {
+ window.location.hash = '#';
+ }
+ $.deck('.slide');
+ });
+
+ it('should start with scaling enabled', function() {
+ expect($.deck('getContainer')).toHaveClass(defaults.classes.scale);
+ });
+
+ describe('disableScale()', function() {
+ it('should remove the scale class from the container', function() {
+ $.deck('disableScale');
+ expect($.deck('getContainer')).not.toHaveClass(defaults.classes.scale);
+ });
+ });
+
+ describe('enableScale()', function() {
+ it('should add the scale class to the container', function() {
+ $.deck('disableScale');
+ $.deck('enableScale');
+ expect($.deck('getContainer')).toHaveClass(defaults.classes.scale);
+ });
+ });
+
+ describe('toggleScale()', function() {
+ it('should toggle between adding and removing the scale class', function() {
+ $.deck('toggleScale');
+ expect($.deck('getContainer')).not.toHaveClass(defaults.classes.scale);
+ $.deck('toggleScale');
+ expect($.deck('getContainer')).toHaveClass(defaults.classes.scale);
+ });
+ });
+
+ describe('key bindings', function() {
+ var e;
+ var $d = $(document);
+
+ beforeEach(function() {
+ e = jQuery.Event('keydown.deckscale');
+ });
+
+ it('should toggle scaling if the specified key is pressed', function() {
+ e.which = 83; // s
+ $d.trigger(e);
+ expect($.deck('getContainer')).not.toHaveClass(defaults.classes.scale);
+ $d.trigger(e);
+ expect($.deck('getContainer')).toHaveClass(defaults.classes.scale);
+ });
+ });
+}); \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/test/spec.status.js b/doc/backends/deckjs/deck.js/test/spec.status.js
new file mode 100644
index 00000000..5232f1c8
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/test/spec.status.js
@@ -0,0 +1,60 @@
+describe('Deck JS Status Indicator', function() {
+ beforeEach(function() {
+ loadFixtures('standard.html');
+ if (Modernizr.history) {
+ history.replaceState({}, "", "#")
+ }
+ else {
+ window.location.hash = '#';
+ }
+ $.deck('.slide');
+ });
+
+ it('should show the correct total number of slides', function() {
+ expect($(defaults.selectors.statusTotal)).toHaveText($.deck('getSlides').length);
+ });
+
+ it('should start at the right current slide', function() {
+ expect($(defaults.selectors.statusCurrent)).toHaveText(1);
+ $.deck('go', 2);
+ $.deck('.slide');
+ waitsFor(function() {
+ return $(defaults.selectors.statusCurrent).text() === '3';
+ });
+ });
+
+ it('should update to the correct number on slide change', function() {
+ $.deck('go', 2);
+ expect($(defaults.selectors.statusCurrent)).toHaveText('3');
+ });
+});
+
+describe('countNested false indicator', function() {
+ beforeEach(function() {
+ loadFixtures('nesteds.html');
+ if (Modernizr.history) {
+ history.replaceState({}, "", "#")
+ }
+ else {
+ window.location.hash = '#';
+ }
+ $.deck('.slide', {
+ countNested: false
+ });
+ });
+
+ it('should ignore nested slides in the total', function() {
+ expect($(defaults.selectors.statusTotal)).toHaveText('5');
+ });
+
+ it('should update to the root slide number when nested becomes active', function() {
+ $.deck('go', 10);
+ expect($(defaults.selectors.statusCurrent)).toHaveText('4');
+ $.deck('prev');
+ expect($(defaults.selectors.statusCurrent)).toHaveText('3');
+ $.deck('go', 3);
+ expect($(defaults.selectors.statusCurrent)).toHaveText('3');
+ $.deck('go', 1);
+ expect($(defaults.selectors.statusCurrent)).toHaveText('2');
+ });
+}); \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/themes/style/_reset.scss b/doc/backends/deckjs/deck.js/themes/style/_reset.scss
new file mode 100644
index 00000000..b1583866
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/style/_reset.scss
@@ -0,0 +1,300 @@
+/* Resets and base styles from HTML5 Boilerplate */
+div, span, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
+small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+
+blockquote, q {
+ quotes:none;
+
+ &:before, &:after {
+ content:"";
+ content:none;
+ }
+}
+
+ins {
+ background-color:#ff9;
+ color:#000;
+ text-decoration:none;
+}
+
+mark {
+ background-color:#ff9;
+ color:#000;
+ font-style:italic;
+ font-weight:bold;
+}
+
+del {
+ text-decoration:line-through;
+}
+
+abbr[title], dfn[title] {
+ border-bottom:1px dotted;
+ cursor:help;
+}
+
+table {
+ border-collapse:collapse;
+ border-spacing:0;
+}
+
+hr {
+ display:block;
+ height:1px;
+ border:0;
+ border-top:1px solid #ccc;
+ margin:1em 0;
+ padding:0;
+}
+
+input, select {
+ vertical-align:middle;
+}
+
+select, input, textarea, button {
+ font:99% sans-serif;
+}
+
+pre, code, kbd, samp {
+ font-family:monospace, sans-serif;
+}
+
+a {
+ -webkit-tap-highlight-color:rgba(0,0,0,0);
+
+ &:hover, &:active {
+ outline:none;
+ }
+}
+
+ul, ol {
+ margin-left:2em;
+ vertical-align:top;
+}
+
+ol {
+ list-style-type:decimal;
+}
+
+nav {
+ ul, li {
+ margin:0;
+ list-style:none;
+ list-style-image:none;
+ }
+}
+
+small {
+ font-size:85%;
+}
+
+strong, th {
+ font-weight:bold;
+}
+
+td {
+ vertical-align:top;
+}
+
+sub, sup {
+ font-size:75%;
+ line-height:0;
+ position:relative;
+}
+
+sup {
+ top:-0.5em;
+}
+
+sub { bottom: -0.25em; }
+
+textarea {
+ overflow:auto;
+}
+
+input[type="radio"] {
+ vertical-align:text-bottom;
+}
+
+input[type="checkbox"] {
+ vertical-align:bottom;
+}
+
+label,
+input[type="button"],
+input[type="submit"],
+input[type="image"],
+button {
+ cursor:pointer;
+}
+
+button, input, select, textarea {
+ margin: 0;
+}
+
+input, textarea {
+ &:invalid {
+ border-radius:1px;
+ -moz-box-shadow:0px 0px 5px red;
+ -webkit-box-shadow:0px 0px 5px red;
+ box-shadow: 0px 0px 5px red;
+
+ .no-boxshadow {
+ background-color: #f0dddd;
+ }
+ }
+}
+
+button {
+ width:auto;
+ overflow:visible;
+}
+
+select, input, textarea {
+ color: #444 ;
+}
+
+a {
+ color:#607890;
+
+ &:hover, &:focus {
+ color:#036;
+ }
+
+ &:link {
+ -webkit-tap-highlight-color: #fff;
+ }
+}
+/* End HTML5 Boilerplate adaptations */
+
+h1 {
+ font-size:4.5em;
+}
+
+h1, .vcenter {
+ font-weight:bold;
+ text-align:center;
+ padding-top:1em;
+ max-height:100%;
+
+ .csstransforms & {
+ padding:0 48px;
+ position:absolute;
+ left:0;
+ right:0;
+ top:50%;
+ -webkit-transform:translate(0, -50%);
+ -moz-transform:translate(0, -50%);
+ -ms-transform:translate(0, -50%);
+ -o-transform:translate(0, -50%);
+ transform:translate(0, -50%);
+ }
+}
+
+.vcenter h1 {
+ position:relative;
+ top:auto;
+ padding:0;
+ -webkit-transform:none;
+ -moz-transform:none;
+ -ms-transform:none;
+ -o-transform:none;
+ transform:none;
+}
+
+h2 {
+ font-size:2.25em;
+ font-weight:bold;
+ padding-top:.5em;
+ margin:0 0 .66666em 0;
+ border-bottom:3px solid #888;
+}
+
+h3 {
+ font-size:1.4375em;
+ font-weight:bold;
+ margin-bottom:.30435em;
+}
+
+h4 {
+ font-size:1.25em;
+ font-weight:bold;
+ margin-bottom:.25em;
+}
+
+h5 {
+ font-size:1.125em;
+ font-weight:bold;
+ margin-bottom:.2222em;
+}
+
+h6 {
+ font-size:1em;
+ font-weight:bold;
+}
+
+img, iframe, video {
+ display:block;
+ max-width:100%;
+}
+
+video, iframe, img {
+ display:block;
+ margin:0 auto;
+}
+
+p, blockquote, iframe, img, ul, ol, pre, video {
+ margin-bottom:1em;
+}
+
+pre {
+ white-space:pre;
+ white-space:pre-wrap;
+ word-wrap:break-word;
+ padding: 1em;
+ border:1px solid #888;
+}
+
+em {
+ font-style:italic;
+}
+
+li {
+ padding:.25em 0;
+ vertical-align:middle;
+
+ > ol, > ul {
+ margin-bottom:inherit;
+ }
+}
+
+.deck-container {
+ font-size:16px;
+ line-height:1.25;
+ color:#444;
+}
+
+.slide {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width:100%;
+} \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/themes/style/beamer.css b/doc/backends/deckjs/deck.js/themes/style/beamer.css
new file mode 100644
index 00000000..73d1f0d9
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/style/beamer.css
@@ -0,0 +1,286 @@
+.deck-container {
+ font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;
+ font-size: 1.3em;
+ background: white;
+ /* Old browsers */
+ background: -moz-linear-gradient(top, #f5f6f7 0%, #dcdcdf 100%);
+ /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f5f6f7), color-stop(100%, #dcdcdf));
+ /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #f5f6f7 0%, #dcdcdf 100%);
+ /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #f5f6f7 0%, #dcdcdf 100%);
+ /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #f5f6f7 0%, #dcdcdf 100%);
+ /* IE10+ */
+ background: linear-gradient(top, #f5f6f7 0%, #dcdcdf 100%);
+ /* W3C */
+ background-attachment: fixed;
+ position: absolute;
+ display: block;
+ top: 0px;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: 100%;
+ margin: 0px;
+ padding: 0px; }
+ .deck-container section.slide {
+ text-shadow: 0px 2px 3px rgba(0, 0, 0, 0.5);
+ padding-top: 40px;
+ margin: 0px; }
+ .deck-container h1, .deck-container h2, .deck-container h3, .deck-container h4, .deck-container h5 {
+ border: 0px;
+ position: relative; }
+ .deck-container h1 {
+ font-size: 3.5em;
+ text-align: center;
+ color: #050014;
+ padding-top: 0.9em;
+ padding-bottom: 3.9em; }
+ .csstransforms .deck-container h1 {
+ position: relative;
+ top: auto;
+ -webkit-transform: none;
+ -moz-transform: none;
+ -ms-transform: none;
+ -o-transform: none;
+ transform: none; }
+ .deck-container h2, .deck-container h3 {
+ font-size: 2.10em;
+ font-weight: bold;
+ padding-top: .5em;
+ margin: 0 0 .66666em 0;
+ color: #050014; }
+ .deck-container pre {
+ border-color: #cde;
+ background: #fff;
+ position: relative;
+ z-index: auto;
+ /* http://nicolasgallagher.com/css-drop-shadows-without-images/ */ }
+ .borderradius .deck-container pre {
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px; }
+ .csstransforms.boxshadow .deck-container pre > :first-child:before {
+ content: "";
+ position: absolute;
+ z-index: -1;
+ background: #fff;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0; }
+ .csstransforms.boxshadow .deck-container pre:before, .csstransforms.boxshadow .deck-container pre:after {
+ content: "";
+ position: absolute;
+ z-index: -2;
+ bottom: 15px;
+ width: 50%;
+ height: 20%;
+ max-width: 300px;
+ -webkit-box-shadow: 0 15px 10px rgba(0, 0, 0, 0.7);
+ -moz-box-shadow: 0 15px 10px rgba(0, 0, 0, 0.7);
+ box-shadow: 0 15px 10px rgba(0, 0, 0, 0.7); }
+ .csstransforms.boxshadow .deck-container pre:before {
+ left: 10px;
+ -webkit-transform: rotate(-3deg);
+ -moz-transform: rotate(-3deg);
+ -ms-transform: rotate(-3deg);
+ -o-transform: rotate(-3deg);
+ transform: rotate(-3deg); }
+ .csstransforms.boxshadow .deck-container pre:after {
+ right: 10px;
+ -webkit-transform: rotate(3deg);
+ -moz-transform: rotate(3deg);
+ -ms-transform: rotate(3deg);
+ -o-transform: rotate(3deg);
+ transform: rotate(3deg); }
+ .deck-container code {
+ color: #789; }
+ .deck-container blockquote {
+ font-family: "Hoefler Text", Constantia, Palatino, "Palatino Linotype", "Book Antiqua", Georgia, serif;
+ font-size: 2em;
+ padding: 1em 2em .5em 2em;
+ color: #000;
+ background: #fff;
+ position: relative;
+ border: 1px solid #cde;
+ z-index: auto; }
+ .borderradius .deck-container blockquote {
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px; }
+ .boxshadow .deck-container blockquote > :first-child:before {
+ content: "";
+ position: absolute;
+ z-index: -1;
+ background: #fff;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0; }
+ .boxshadow .deck-container blockquote:after {
+ content: "";
+ position: absolute;
+ z-index: -2;
+ top: 10px;
+ bottom: 10px;
+ left: 0;
+ right: 50%;
+ -moz-border-radius: 10px/100px;
+ border-radius: 10px/100px;
+ -webkit-box-shadow: 0 0 15px rgba(0, 0, 0, 0.6);
+ -moz-box-shadow: 0 0 15px rgba(0, 0, 0, 0.6);
+ box-shadow: 0 0 15px rgba(0, 0, 0, 0.6); }
+ .deck-container blockquote p {
+ margin: 0; }
+ .deck-container blockquote cite {
+ font-size: .5em;
+ font-style: normal;
+ font-weight: bold;
+ color: #888; }
+ .deck-container blockquote:before {
+ content: "“";
+ position: absolute;
+ top: 0;
+ left: 0;
+ font-size: 5em;
+ line-height: 1;
+ color: #ccf0f0;
+ z-index: 1; }
+ .deck-container .borderradius img {
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px; }
+ .deck-container ::-moz-selection {
+ background: #08455f;
+ color: #fff; }
+ .deck-container ::selection {
+ background: #08455f;
+ color: #fff; }
+ .deck-container a, .deck-container a:hover, .deck-container a:focus, .deck-container a:active, .deck-container a:visited {
+ color: #599;
+ text-decoration: none; }
+ .deck-container a:hover, .deck-container a:focus {
+ text-decoration: underline; }
+ .deck-container .deck-prev-link, .deck-container .deck-next-link {
+ background: #fff;
+ opacity: 0.5; }
+ .deck-container .deck-prev-link, .deck-container .deck-prev-link:hover, .deck-container .deck-prev-link:focus, .deck-container .deck-prev-link:active, .deck-container .deck-prev-link:visited, .deck-container .deck-next-link, .deck-container .deck-next-link:hover, .deck-container .deck-next-link:focus, .deck-container .deck-next-link:active, .deck-container .deck-next-link:visited {
+ color: #599; }
+ .deck-container .deck-prev-link:hover, .deck-container .deck-prev-link:focus, .deck-container .deck-next-link:hover, .deck-container .deck-next-link:focus {
+ opacity: 1;
+ text-decoration: none; }
+ .deck-container .deck-status {
+ position: absolute;
+ display: block;
+ z-index: 20;
+ left: 0px;
+ right: 0px;
+ bottom: 0px;
+ width: 100%;
+ font-size: 0.6666em;
+ background-color: black;
+ -webkit-box-shadow: 0px -1px 1px rgba(255, 255, 255, 0.2);
+ -moz-box-shadow: 0px -1px 1px rgba(255, 255, 255, 0.2);
+ box-shadow: 0px -1px 1px rgba(255, 255, 255, 0.2);
+ color: white; }
+ .deck-container .deck-toc-status {
+ position: absolute;
+ display: block;
+ z-index: 10;
+ left: 0px;
+ right: 0px;
+ top: 0px;
+ width: 100%;
+ font-size: 0.6666em;
+ background-color: black;
+ -webkit-box-shadow: 0px 1px 1px rgba(255, 255, 255, 0.2);
+ -moz-box-shadow: 0px 1px 1px rgba(255, 255, 255, 0.2);
+ box-shadow: 0px 1px 1px rgba(255, 255, 255, 0.2);
+ color: white; }
+ .deck-container.deck-menu {
+ background: #EAEFF7;
+ overflow: scroll; }
+ .deck-container.deck-menu .slide {
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+ -webkit-box-shadow: 5px 15px 20px rgba(0, 0, 0, 0.2);
+ -moz-box-shadow: 5px 15px 20px rgba(0, 0, 0, 0.2);
+ box-shadow: 5px 15px 20px rgba(0, 0, 0, 0.2);
+ z-index: 10; }
+ .rgba .deck-container.deck-menu .slide {
+ background: rgba(0, 0, 0, 0.1); }
+ .deck-container.deck-menu .slide.deck-current, .rgba .deck-container.deck-menu .slide.deck-current, .no-touch .deck-container.deck-menu .slide:hover {
+ background: #fff; }
+ .deck-container.deck-menu .deck-status, .deck-container.deck-menu .deck-toc-status {
+ visibility: hidden !important; }
+ .deck-container .deck-prev-link, .deck-container .deck-next-link {
+ display: none;
+ position: absolute;
+ z-index: 3;
+ bottom: 38px;
+ width: 24px;
+ height: 24px;
+ line-height: 24px;
+ background: #fff;
+ text-align: center;
+ color: #aaa;
+ text-decoration: none;
+ border: 1px solid #ddd;
+ font-weight: bold;
+ -webkit-border-radius: 20px;
+ -moz-border-radius: 20px;
+ border-radius: 20px; }
+ .no-boxshadow .deck-container .deck-prev-link:hover, .no-boxshadow .deck-container .deck-prev-link:focus, .no-boxshadow .deck-container .deck-next-link:hover, .no-boxshadow .deck-container .deck-next-link:focus {
+ border-color: #999;
+ color: #444; }
+ .deck-container .deck-prev-link:after, .deck-container .deck-next-link:after {
+ text-shadow: none;
+ background: rgba(0, 0, 0, 0.5);
+ color: #fff;
+ font-size: 12px;
+ font-weight: normal;
+ height: 18px;
+ line-height: 18px;
+ padding: 0 6px;
+ position: absolute;
+ top: -25px; }
+ .deck-container .deck-prev-link:before, .deck-container .deck-next-link:before {
+ display: block;
+ position: absolute;
+ top: -7px;
+ width: 0;
+ height: 0;
+ border: 5px solid rgba(0, 0, 0, 0.5);
+ border-color: rgba(0, 0, 0, 0.5) transparent transparent transparent; }
+ .deck-container .deck-prev-link {
+ left: 10px; }
+ .boxshadow .deck-container .deck-prev-link:hover, .boxshadow .deck-container .deck-prev-link:focus {
+ bottom: 37px;
+ margin-left: 0px; }
+ .deck-container .deck-prev-link:after {
+ right: -10px; }
+ .deck-container .deck-prev-link:before {
+ right: 7px; }
+ .deck-container .deck-next-link {
+ right: 10px; }
+ .boxshadow .deck-container .deck-next-link:hover, .boxshadow .deck-container .deck-next-link:focus {
+ bottom: 37px;
+ margin-left: 0px; }
+ .deck-container .deck-next-link:after {
+ left: -10px; }
+ .deck-container .deck-next-link:before {
+ left: 7px; }
+ .deck-container .goto-form {
+ background: #fff;
+ border: 1px solid #cde;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px; }
+ .boxshadow .deck-container .goto-form {
+ -webkit-box-shadow: 0 15px 10px -10px rgba(0, 0, 0, 0.5), 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
+ -moz-box-shadow: 0 15px 10px -10px rgba(0, 0, 0, 0.5), 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
+ box-shadow: 0 15px 10px -10px rgba(0, 0, 0, 0.5), 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset; }
diff --git a/doc/backends/deckjs/deck.js/themes/style/beamer.scss b/doc/backends/deckjs/deck.js/themes/style/beamer.scss
new file mode 100644
index 00000000..975e5072
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/style/beamer.scss
@@ -0,0 +1,385 @@
+$background_color_light: rgba(245,246,247,1);
+$background_color_dark: rgba(220,220,223,1);
+
+@mixin border-radius($r) {
+ -webkit-border-radius:$r;
+ -moz-border-radius:$r;
+ border-radius:$r;
+}
+
+@mixin rotate($deg) {
+ -webkit-transform: rotate($deg);
+ -moz-transform: rotate($deg);
+ -ms-transform: rotate($deg);
+ -o-transform: rotate($deg);
+ transform: rotate($deg);
+}
+
+@mixin box-shadow($x, $y, $blur, $color) {
+ -webkit-box-shadow:$x $y $blur $color;
+ -moz-box-shadow:$x $y $blur $color;
+ box-shadow:$x $y $blur $color;
+}
+
+@mixin linear-gradient-background($light, $dark, $default) {
+ background: rgb($default,$default,$default); /* Old browsers */
+ background: -moz-linear-gradient(top, $light 0%, $dark 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,$light), color-stop(100%,$dark)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, $light 0%,$dark 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, $light 0%,$dark 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, $light 0%,$dark 100%); /* IE10+ */
+ background: linear-gradient(top, $light 0%,$dark 100%); /* W3C */
+}
+
+.deck-container {
+ //font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
+ font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;
+ font-size: 1.3em;
+ @include linear-gradient-background($background_color_light, $background_color_dark, 255);
+ background-attachment: fixed;
+ position: absolute;
+ display: block;
+ top: 0px;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+
+
+ section.slide {
+ text-shadow: 0px 2px 3px rgba(0,0,0,.5);
+ //padding-left: 40px;
+ padding-top: 40px;
+ margin: 0px;
+ }
+
+ h1,h2,h3,h4,h5 {
+ border: 0px;
+ position: relative;
+ }
+
+ h1 {
+ font-size: 3.5em;
+ text-align: center;
+ color: #050014;
+ padding-top: 0.9em;
+ padding-bottom: 3.9em;
+
+ .csstransforms & {
+ position: relative;
+ top: auto;
+ -webkit-transform: none;
+ -moz-transform: none;
+ -ms-transform: none;
+ -o-transform: none;
+ transform: none;
+ }
+ }
+
+ h2, h3 {
+ font-size: 2.10em;
+ font-weight: bold;
+ padding-top:.5em;
+ margin: 0 0 .66666em 0;
+ color: #050014;
+ }
+
+ pre {
+ border-color: #cde;
+ background: #fff;
+ position: relative;
+ z-index: auto;
+
+ .borderradius & {
+ @include border-radius(5px);
+ }
+
+ /* http://nicolasgallagher.com/css-drop-shadows-without-images/ */
+ .csstransforms.boxshadow & {
+ > :first-child:before {
+ content:"";
+ position: absolute;
+ z-index: -1;
+ background: #fff;
+ top:0;
+ bottom:0;
+ left:0;
+ right:0;
+ }
+
+ &:before, &:after {
+ content:"";
+ position: absolute;
+ z-index: -2;
+ bottom:15px;
+ width:50%;
+ height:20%;
+ max-width:300px;
+ @include box-shadow(0, 15px, 10px, rgba(0, 0, 0, 0.7));
+ }
+
+ &:before {
+ left:10px;
+ @include rotate(-3deg);
+ }
+
+ &:after {
+ right:10px;
+ @include rotate(3deg);
+ }
+ }
+ }
+
+ code {
+ color:#789;
+ }
+
+ blockquote {
+ font-family: "Hoefler Text", Constantia, Palatino, "Palatino Linotype", "Book Antiqua", Georgia, serif;
+ font-size: 2em;
+ padding: 1em 2em .5em 2em;
+ color: #000;
+ background: #fff;
+ position: relative;
+ border:1px solid #cde;
+ z-index: auto;
+
+ .borderradius & {
+ @include border-radius(5px);
+ }
+
+ .boxshadow & {
+ > :first-child:before {
+ content: "";
+ position: absolute;
+ z-index: -1;
+ background: #fff;
+ top:0;
+ bottom:0;
+ left:0;
+ right:0;
+ }
+
+ &:after {
+ content: "";
+ position: absolute;
+ z-index: -2;
+ top: 10px;
+ bottom: 10px;
+ left: 0;
+ right: 50%;
+ -moz-border-radius: 10px / 100px;
+ border-radius: 10px / 100px;
+ @include box-shadow(0, 0, 15px, rgba(0,0,0,0.6));
+ }
+ }
+
+ p {
+ margin:0;
+ }
+
+ cite {
+ font-size:.5em;
+ font-style:normal;
+ font-weight:bold;
+ color:#888;
+ }
+
+ &:before {
+ content:"“";
+ position: absolute;
+ top:0;
+ left:0;
+ font-size:5em;
+ line-height:1;
+ color: #ccf0f0;
+ z-index:1;
+ }
+ }
+
+ .borderradius img {
+ @include border-radius(5px);
+ }
+
+ ::-moz-selection{ background:#08455f; color:#fff; }
+ ::selection { background:#08455f; color:#fff; }
+
+ a {
+ &, &:hover, &:focus, &:active, &:visited {
+ color:#599;
+ text-decoration:none;
+ }
+
+ &:hover, &:focus {
+ text-decoration:underline;
+ }
+ }
+
+ .deck-prev-link, .deck-next-link {
+ background: #fff;
+ opacity: 0.5;
+
+ &, &:hover, &:focus, &:active, &:visited {
+ color: #599;
+ }
+
+ &:hover, &:focus {
+ opacity:1;
+ text-decoration: none;
+ }
+ }
+
+ .deck-status {
+ position: absolute;
+ display: block;
+ z-index: 20;
+ left: 0px;
+ right: 0px;
+ bottom: 0px;
+ width: 100%;
+ font-size:0.6666em;
+ background-color: black;
+ @include box-shadow(0px, -1px, 1px, rgba(255, 255, 255, 0.2));
+ color: white;
+ }
+
+ .deck-toc-status {
+ position: absolute;
+ display: block;
+ z-index: 10;
+ left: 0px;
+ right: 0px;
+ top: 0px;
+ width: 100%;
+ font-size:0.6666em;
+ background-color: black;
+ @include box-shadow(0px, 1px, 1px, rgba(255, 255, 255, 0.2));
+ color: white;
+ }
+
+ &.deck-menu {
+ background: #EAEFF7;
+ overflow: scroll;
+
+ .slide {
+ @include border-radius(5px);
+ @include box-shadow(5px, 15px, 20px, rgba(0, 0, 0, 0.2));
+ z-index: 10;
+
+ .rgba & {
+ background: rgba(0,0,0,.1);
+ }
+
+ &.deck-current, .rgba &.deck-current, .no-touch &:hover {
+ background: #fff;
+ }
+ }
+
+ .deck-status, .deck-toc-status {
+ visibility: hidden !important;
+ }
+ }
+
+ .deck-prev-link, .deck-next-link {
+ display: none;
+ position: absolute;
+ z-index: 3;
+ bottom: 38px;
+ width: 24px;
+ height: 24px;
+ line-height: 24px;
+ background: #fff;
+ text-align: center;
+ color: #aaa;
+ text-decoration: none;
+ border: 1px solid #ddd;
+ font-weight: bold;
+ @include border-radius(20px);
+
+ .no-boxshadow & {
+ &:hover, &:focus {
+ border-color: #999;
+ color: #444;
+ }
+ }
+
+ &:after {
+ //content: "";
+ text-shadow: none;
+ background: rgba(0,0,0,.5);
+ color: #fff;
+ font-size: 12px;
+ font-weight: normal;
+ height: 18px;
+ line-height: 18px;
+ padding: 0 6px;
+ position: absolute;
+ top: -25px;
+ }
+
+ &:before {
+ //content:"";
+ display: block;
+ position: absolute;
+ top: -7px;
+ width: 0;
+ height: 0;
+ border: 5px solid rgba(0,0,0,.5);
+ border-color: rgba(0,0,0,.5) transparent transparent transparent;
+ }
+ }
+
+ .deck-prev-link {
+ left: 10px;
+
+ .boxshadow & {
+ &:hover, &:focus {
+ bottom:37px;
+ margin-left: 0px;
+ }
+ }
+
+ &:after {
+ right: -10px;
+ }
+
+ &:before {
+ right:7px;
+ }
+ }
+
+ .deck-next-link {
+ right: 10px;
+
+ .boxshadow & {
+ &:hover, &:focus {
+ bottom: 37px;
+ margin-left: 0px;
+ }
+ }
+
+ &:after {
+ left: -10px;
+ }
+
+ &:before {
+ left:7px;
+ }
+ }
+
+ .goto-form {
+ background:#fff;
+ border:1px solid #cde;
+ @include border-radius(5px);
+
+ .boxshadow & {
+ -webkit-box-shadow: 0 15px 10px -10px rgba(0, 0, 0, 0.5), 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
+ -moz-box-shadow: 0 15px 10px -10px rgba(0, 0, 0, 0.5), 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
+ box-shadow: 0 15px 10px -10px rgba(0, 0, 0, 0.5), 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
+ }
+ }
+}
+
+
diff --git a/doc/backends/deckjs/deck.js/themes/style/neon.css b/doc/backends/deckjs/deck.js/themes/style/neon.css
new file mode 100644
index 00000000..3bd5c6ef
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/style/neon.css
@@ -0,0 +1,421 @@
+/* Resets and base styles from HTML5 Boilerplate */
+div, span, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
+small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after, q:before, q:after {
+ content: "";
+ content: none;
+}
+
+ins {
+ background-color: #ff9;
+ color: #000;
+ text-decoration: none;
+}
+
+mark {
+ background-color: #ff9;
+ color: #000;
+ font-style: italic;
+ font-weight: bold;
+}
+
+del {
+ text-decoration: line-through;
+}
+
+abbr[title], dfn[title] {
+ border-bottom: 1px dotted;
+ cursor: help;
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+hr {
+ display: block;
+ height: 1px;
+ border: 0;
+ border-top: 1px solid #ccc;
+ margin: 1em 0;
+ padding: 0;
+}
+
+input, select {
+ vertical-align: middle;
+}
+
+select, input, textarea, button {
+ font: 99% sans-serif;
+}
+
+pre, code, kbd, samp {
+ font-family: monospace, sans-serif;
+}
+
+a {
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+a:hover, a:active {
+ outline: none;
+}
+
+ul, ol {
+ margin-left: 2em;
+ vertical-align: top;
+}
+
+ol {
+ list-style-type: decimal;
+}
+
+nav ul, nav li {
+ margin: 0;
+ list-style: none;
+ list-style-image: none;
+}
+
+small {
+ font-size: 85%;
+}
+
+strong, th {
+ font-weight: bold;
+}
+
+td {
+ vertical-align: top;
+}
+
+sub, sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+textarea {
+ overflow: auto;
+}
+
+input[type="radio"] {
+ vertical-align: text-bottom;
+}
+
+input[type="checkbox"] {
+ vertical-align: bottom;
+}
+
+label,
+input[type="button"],
+input[type="submit"],
+input[type="image"],
+button {
+ cursor: pointer;
+}
+
+button, input, select, textarea {
+ margin: 0;
+}
+
+input:invalid, textarea:invalid {
+ border-radius: 1px;
+ -moz-box-shadow: 0px 0px 5px red;
+ -webkit-box-shadow: 0px 0px 5px red;
+ box-shadow: 0px 0px 5px red;
+}
+input:invalid .no-boxshadow, textarea:invalid .no-boxshadow {
+ background-color: #f0dddd;
+}
+
+button {
+ width: auto;
+ overflow: visible;
+}
+
+select, input, textarea {
+ color: #444444;
+}
+
+a {
+ color: #607890;
+}
+a:hover, a:focus {
+ color: #036;
+}
+a:link {
+ -webkit-tap-highlight-color: #fff;
+}
+
+/* End HTML5 Boilerplate adaptations */
+h1 {
+ font-size: 4.5em;
+}
+
+h1, .vcenter {
+ font-weight: bold;
+ text-align: center;
+ padding-top: 1em;
+ max-height: 100%;
+}
+.csstransforms h1, .csstransforms .vcenter {
+ padding: 0 48px;
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 50%;
+ -webkit-transform: translate(0, -50%);
+ -moz-transform: translate(0, -50%);
+ -ms-transform: translate(0, -50%);
+ -o-transform: translate(0, -50%);
+ transform: translate(0, -50%);
+}
+
+.vcenter h1 {
+ position: relative;
+ top: auto;
+ padding: 0;
+ -webkit-transform: none;
+ -moz-transform: none;
+ -ms-transform: none;
+ -o-transform: none;
+ transform: none;
+}
+
+h2 {
+ font-size: 2.25em;
+ font-weight: bold;
+ padding-top: .5em;
+ margin: 0 0 .66666em 0;
+ border-bottom: 3px solid #888;
+}
+
+h3 {
+ font-size: 1.4375em;
+ font-weight: bold;
+ margin-bottom: .30435em;
+}
+
+h4 {
+ font-size: 1.25em;
+ font-weight: bold;
+ margin-bottom: .25em;
+}
+
+h5 {
+ font-size: 1.125em;
+ font-weight: bold;
+ margin-bottom: .2222em;
+}
+
+h6 {
+ font-size: 1em;
+ font-weight: bold;
+}
+
+img, iframe, video {
+ display: block;
+ max-width: 100%;
+}
+
+video, iframe, img {
+ display: block;
+ margin: 0 auto;
+}
+
+p, blockquote, iframe, img, ul, ol, pre, video {
+ margin-bottom: 1em;
+}
+
+pre {
+ white-space: pre;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ padding: 1em;
+ border: 1px solid #888;
+}
+
+em {
+ font-style: italic;
+}
+
+li {
+ padding: .25em 0;
+ vertical-align: middle;
+}
+li > ol, li > ul {
+ margin-bottom: inherit;
+}
+
+.deck-container {
+ font-size: 16px;
+ line-height: 1.25;
+ color: #444;
+}
+
+.slide {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+}
+
+h1 {
+ color: #0af;
+ font-weight: normal;
+ font-weight: 100;
+ text-shadow: 0 0 50px #0af, 0 0 3px #fff;
+}
+
+h2 {
+ color: #af0;
+ border-bottom-color: #ccc;
+ font-weight: normal;
+ font-weight: 100;
+ text-shadow: 0 0 15px #af0, 0 0 2px #fff;
+ border-bottom: 1px solid #333;
+}
+
+h3 {
+ color: #fff;
+ font-weight: normal;
+ font-weight: 100;
+ text-shadow: 0 0 10px #fff, 0 0 2px #fff;
+}
+
+pre {
+ border-color: #333;
+}
+pre code {
+ color: #fff;
+}
+
+code {
+ color: #f0a;
+}
+
+blockquote {
+ font-size: 2em;
+ padding: 1em 2em;
+ color: #fff;
+ border-left: 5px solid #fff;
+}
+blockquote p {
+ margin: 0;
+}
+blockquote cite {
+ font-size: .5em;
+ font-style: normal;
+ font-weight: normal;
+ font-weight: 100;
+ color: #aaa;
+ text-shadow: 0 0 15px #fff, 0 0 2px #fff;
+}
+
+::-moz-selection {
+ background: #a0f;
+}
+
+::selection {
+ background: #a0f;
+}
+
+a, a:hover, a:focus, a:active, a:visited {
+ color: #f0a;
+ text-decoration: none;
+}
+a:hover, a:focus {
+ text-decoration: underline;
+}
+
+.deck-container {
+ font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
+ font-size: 1.75em;
+ color: #aaa;
+ background: #000;
+}
+.deck-container > .slide {
+ padding: 0 48px;
+}
+
+.slide .deck-before, .slide .deck-previous {
+ opacity: 0.4;
+}
+.slide .deck-before:not(.deck-child-current) .deck-before, .slide .deck-before:not(.deck-child-current) .deck-previous, .slide .deck-previous:not(.deck-child-current) .deck-before, .slide .deck-previous:not(.deck-child-current) .deck-previous {
+ opacity: 1;
+}
+.slide .deck-child-current {
+ opacity: 1;
+}
+
+.deck-prev-link, .deck-next-link {
+ background: #f0a;
+ text-shadow: 0 0 3px #fff;
+}
+.deck-prev-link, .deck-prev-link:hover, .deck-prev-link:focus, .deck-prev-link:active, .deck-prev-link:visited, .deck-next-link, .deck-next-link:hover, .deck-next-link:focus, .deck-next-link:active, .deck-next-link:visited {
+ color: #fff;
+}
+.deck-prev-link:hover, .deck-prev-link:focus, .deck-next-link:hover, .deck-next-link:focus {
+ text-decoration: none;
+ box-shadow: 0 0 20px #f0a, 0 0 5px #fff;
+}
+
+.deck-status {
+ font-size: 0.6666em;
+}
+
+.goto-form {
+ background: #000;
+ border: 1px solid #f0a;
+}
+.goto-form label {
+ color: #fff;
+}
+
+.deck-menu .slide {
+ background: #333;
+}
+.deck-menu .deck-current {
+ background: #444;
+}
+.boxshadow .deck-menu .deck-current {
+ background: #000;
+ box-shadow: 0 0 20px #f0a, 0 0 5px #fff;
+}
+.no-touch .deck-menu .slide:hover {
+ background: #444;
+}
+.no-touch.boxshadow .deck-menu .slide:hover {
+ background: #000;
+ box-shadow: 0 0 20px #f0a, 0 0 5px #fff;
+}
diff --git a/doc/backends/deckjs/deck.js/themes/style/neon.scss b/doc/backends/deckjs/deck.js/themes/style/neon.scss
new file mode 100644
index 00000000..1631950e
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/style/neon.scss
@@ -0,0 +1,148 @@
+@import "reset";
+
+h1 {
+ color:#0af;
+ font-weight:normal;
+ font-weight:100;
+ text-shadow:0 0 50px #0af, 0 0 3px #fff;
+}
+
+h2 {
+ color:#af0;
+ border-bottom-color:#ccc;
+ font-weight:normal;
+ font-weight:100;
+ text-shadow:0 0 15px #af0, 0 0 2px #fff;
+ border-bottom:1px solid #333;
+}
+
+h3 {
+ color:#fff;
+ font-weight:normal;
+ font-weight:100;
+ text-shadow:0 0 10px #fff, 0 0 2px #fff;
+}
+
+pre {
+ border-color:#333;
+
+ code {
+ color:#fff;
+ }
+}
+
+code {
+ color:#f0a;
+}
+
+blockquote {
+ font-size:2em;
+ padding:1em 2em;
+ color:#fff;
+ border-left:5px solid #fff;
+
+ p {
+ margin:0;
+ }
+
+ cite {
+ font-size:.5em;
+ font-style:normal;
+ font-weight:normal;
+ font-weight:100;
+ color:#aaa;
+ text-shadow:0 0 15px #fff, 0 0 2px #fff;
+ }
+}
+
+::-moz-selection{ background:#a0f; }
+::selection { background:#a0f; }
+
+a {
+ &, &:hover, &:focus, &:active, &:visited {
+ color:#f0a;
+ text-decoration:none;
+ }
+
+ &:hover, &:focus {
+ text-decoration:underline;
+ }
+}
+
+.deck-container {
+ font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
+ font-size:1.75em;
+ color:#aaa;
+ background:#000;
+
+ > .slide {
+ padding:0 48px;
+ }
+}
+
+.slide {
+ .deck-before, .deck-previous {
+ opacity:0.4;
+
+ &:not(.deck-child-current) {
+ .deck-before, .deck-previous {
+ opacity:1;
+ }
+ }
+ }
+
+ .deck-child-current {
+ opacity:1;
+ }
+}
+
+.deck-prev-link, .deck-next-link {
+ background:#f0a;
+ text-shadow:0 0 3px #fff;
+
+ &, &:hover, &:focus, &:active, &:visited {
+ color:#fff;
+ }
+
+ &:hover, &:focus {
+ text-decoration:none;
+ box-shadow:0 0 20px #f0a, 0 0 5px #fff;
+ }
+}
+
+.deck-status {
+ font-size:0.6666em;
+}
+
+.goto-form {
+ background:#000;
+ border:1px solid #f0a;
+
+ label {
+ color:#fff;
+ }
+}
+
+.deck-menu {
+ .slide {
+ background:#333;
+ }
+
+ .deck-current {
+ background:#444;
+
+ .boxshadow & {
+ background:#000;
+ box-shadow:0 0 20px #f0a, 0 0 5px #fff;
+ }
+ }
+
+ .no-touch & .slide:hover {
+ background:#444;
+ }
+
+ .no-touch.boxshadow & .slide:hover {
+ background:#000;
+ box-shadow:0 0 20px #f0a, 0 0 5px #fff;
+ }
+} \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/themes/style/swiss.css b/doc/backends/deckjs/deck.js/themes/style/swiss.css
new file mode 100644
index 00000000..aaa33e8d
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/style/swiss.css
@@ -0,0 +1,404 @@
+/* Resets and base styles from HTML5 Boilerplate */
+div, span, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
+small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after, q:before, q:after {
+ content: "";
+ content: none;
+}
+
+ins {
+ background-color: #ff9;
+ color: #000;
+ text-decoration: none;
+}
+
+mark {
+ background-color: #ff9;
+ color: #000;
+ font-style: italic;
+ font-weight: bold;
+}
+
+del {
+ text-decoration: line-through;
+}
+
+abbr[title], dfn[title] {
+ border-bottom: 1px dotted;
+ cursor: help;
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+table, th, td {
+ border: 1px solid black;
+}
+
+th {
+
+background-color: #CBD5E8;
+
+}
+
+hr {
+ display: block;
+ height: 1px;
+ border: 0;
+ border-top: 1px solid #ccc;
+ margin: 1em 0;
+ padding: 0;
+}
+
+input, select {
+ vertical-align: middle;
+}
+
+select, input, textarea, button {
+ font: 99% sans-serif;
+}
+
+pre, code, kbd, samp {
+ font-family: monospace, sans-serif;
+}
+
+a {
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+a:hover, a:active {
+ outline: none;
+}
+
+ul, ol {
+ margin-left: 2em;
+ vertical-align: top;
+}
+
+ol {
+ list-style-type: decimal;
+}
+
+nav ul, nav li {
+ margin: 0;
+ list-style: none;
+ list-style-image: none;
+}
+
+small {
+ font-size: 85%;
+}
+
+strong, th {
+ font-weight: bold;
+}
+
+td {
+ vertical-align: top;
+}
+
+sub, sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+textarea {
+ overflow: auto;
+}
+
+input[type="radio"] {
+ vertical-align: text-bottom;
+}
+
+input[type="checkbox"] {
+ vertical-align: bottom;
+}
+
+label,
+input[type="button"],
+input[type="submit"],
+input[type="image"],
+button {
+ cursor: pointer;
+}
+
+button, input, select, textarea {
+ margin: 0;
+}
+
+input:invalid, textarea:invalid {
+ border-radius: 1px;
+ -moz-box-shadow: 0px 0px 5px red;
+ -webkit-box-shadow: 0px 0px 5px red;
+ box-shadow: 0px 0px 5px red;
+}
+input:invalid .no-boxshadow, textarea:invalid .no-boxshadow {
+ background-color: #f0dddd;
+}
+
+button {
+ width: auto;
+ overflow: visible;
+}
+
+select, input, textarea {
+ color: #444444;
+}
+
+a {
+ color: #607890;
+}
+a:hover, a:focus {
+ color: #036;
+}
+a:link {
+ -webkit-tap-highlight-color: #fff;
+}
+
+/* End HTML5 Boilerplate adaptations */
+h1 {
+ font-size: 4.5em;
+}
+
+h1, .vcenter {
+ font-weight: bold;
+ text-align: center;
+ padding-top: 1em;
+ max-height: 100%;
+}
+.csstransforms h1, .csstransforms .vcenter {
+ padding: 0 48px;
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 50%;
+ -webkit-transform: translate(0, -50%);
+ -moz-transform: translate(0, -50%);
+ -ms-transform: translate(0, -50%);
+ -o-transform: translate(0, -50%);
+ transform: translate(0, -50%);
+}
+
+.vcenter h1 {
+ position: relative;
+ top: auto;
+ padding: 0;
+ -webkit-transform: none;
+ -moz-transform: none;
+ -ms-transform: none;
+ -o-transform: none;
+ transform: none;
+}
+
+h2 {
+ font-size: 2.25em;
+ font-weight: bold;
+ padding-top: .5em;
+ margin: 0 0 .66666em 0;
+ border-bottom: 3px solid #888;
+}
+
+h3 {
+ font-size: 1.4375em;
+ font-weight: bold;
+ margin-bottom: .30435em;
+}
+
+h4 {
+ font-size: 1.25em;
+ font-weight: bold;
+ margin-bottom: .25em;
+}
+
+h5 {
+ font-size: 1.125em;
+ font-weight: bold;
+ margin-bottom: .2222em;
+}
+
+h6 {
+ font-size: 1em;
+ font-weight: bold;
+}
+
+img, iframe, video {
+ display: block;
+ max-width: 100%;
+}
+
+video, iframe, img {
+ display: block;
+ margin: 0 auto;
+}
+
+p, blockquote, iframe, img, ul, ol, pre, video {
+ margin-bottom: 1em;
+}
+
+pre {
+ white-space: pre;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ padding: 1em;
+ border: 1px solid #888;
+}
+
+em {
+ font-style: italic;
+}
+
+li {
+ padding: .25em 0;
+ vertical-align: middle;
+}
+li > ol, li > ul {
+ margin-bottom: inherit;
+}
+
+.deck-container {
+ font-size: 16px;
+ line-height: 1.25;
+ color: #444;
+}
+
+.slide {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+}
+
+h1 {
+ color: #0E244B;
+}
+
+div.content {
+ background: #f8f8f8;
+}
+
+
+h2 {
+ color: #c00;
+ border-bottom-color: #ccc;
+}
+
+h3 {
+ color: #888;
+}
+
+pre {
+ border-color: #ccc;
+}
+
+code {
+ color: #888;
+}
+
+blockquote {
+ font-size: 2em;
+ font-style: italic;
+ padding: 1em 2em;
+ color: #000;
+ border-left: 5px solid #ccc;
+}
+blockquote p {
+ margin: 0;
+}
+blockquote cite {
+ font-size: .5em;
+ font-style: normal;
+ font-weight: bold;
+ color: #888;
+}
+
+::-moz-selection {
+ background: #c00;
+ color: #fff;
+}
+
+::selection {
+ background: #c00;
+ color: #fff;
+}
+
+a, a:hover, a:focus, a:active, a:visited {
+ color: #c00;
+ text-decoration: none;
+}
+a:hover, a:focus {
+ text-decoration: underline;
+}
+
+.deck-container {
+ font-family: "Helvetica Neue", sans-serif;
+ font-size: 1.75em;
+ background: #fff;
+}
+.deck-container > .slide {
+ padding: 0 48px;
+}
+
+.slide .deck-before, .slide .deck-previous {
+ opacity: 0.4;
+}
+.slide .deck-before:not(.deck-child-current) .deck-before, .slide .deck-before:not(.deck-child-current) .deck-previous, .slide .deck-previous:not(.deck-child-current) .deck-before, .slide .deck-previous:not(.deck-child-current) .deck-previous {
+ opacity: 1;
+}
+.slide .deck-child-current {
+ opacity: 1;
+}
+
+.deck-prev-link, .deck-next-link {
+ background: #ccc;
+ font-family: serif;
+}
+.deck-prev-link, .deck-prev-link:hover, .deck-prev-link:focus, .deck-prev-link:active, .deck-prev-link:visited, .deck-next-link, .deck-next-link:hover, .deck-next-link:focus, .deck-next-link:active, .deck-next-link:visited {
+ color: #fff;
+}
+.deck-prev-link:hover, .deck-prev-link:focus, .deck-next-link:hover, .deck-next-link:focus {
+ background: #c00;
+ text-decoration: none;
+}
+
+.deck-status {
+ font-size: 0.6666em;
+}
+
+.deck-menu .slide {
+ background: #eee;
+}
+.deck-menu .deck-current, .no-touch .deck-menu .slide:hover {
+ background: #ddf;
+}
diff --git a/doc/backends/deckjs/deck.js/themes/style/swiss.scss b/doc/backends/deckjs/deck.js/themes/style/swiss.scss
new file mode 100644
index 00000000..781574e0
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/style/swiss.scss
@@ -0,0 +1,109 @@
+@import "reset";
+
+h1 {
+ color:#000;
+}
+
+h2 {
+ color:#c00;
+ border-bottom-color:#ccc;
+}
+
+h3 {
+ color:#888;
+}
+
+pre {
+ border-color:#ccc;
+}
+
+code {
+ color:#888;
+}
+
+blockquote {
+ font-size:2em;
+ font-style:italic;
+ padding:1em 2em;
+ color:#000;
+ border-left:5px solid #ccc;
+
+ p {
+ margin:0;
+ }
+
+ cite {
+ font-size:.5em;
+ font-style:normal;
+ font-weight:bold;
+ color:#888;
+ }
+}
+
+::-moz-selection{ background:#c00; color:#fff; }
+::selection { background:#c00; color:#fff; }
+
+a {
+ &, &:hover, &:focus, &:active, &:visited {
+ color:#c00;
+ text-decoration:none;
+ }
+
+ &:hover, &:focus {
+ text-decoration:underline;
+ }
+}
+
+.deck-container {
+ font-family: "Helvetica Neue", sans-serif;
+ font-size:1.75em;
+ background:#fff;
+
+ > .slide {
+ padding:0 48px;
+ }
+}
+
+.slide {
+ .deck-before, .deck-previous {
+ opacity:0.4;
+
+ &:not(.deck-child-current) {
+ .deck-before, .deck-previous {
+ opacity:1;
+ }
+ }
+ }
+
+ .deck-child-current {
+ opacity:1;
+ }
+}
+
+.deck-prev-link, .deck-next-link {
+ background:#ccc;
+ font-family:serif;
+
+ &, &:hover, &:focus, &:active, &:visited {
+ color:#fff;
+ }
+
+ &:hover, &:focus {
+ background:#c00;
+ text-decoration:none;
+ }
+}
+
+.deck-status {
+ font-size:0.6666em;
+}
+
+.deck-menu {
+ .slide {
+ background:#eee;
+ }
+
+ .deck-current, .no-touch & .slide:hover {
+ background:#ddf;
+ }
+}
diff --git a/doc/backends/deckjs/deck.js/themes/style/web-2.0.css b/doc/backends/deckjs/deck.js/themes/style/web-2.0.css
new file mode 100644
index 00000000..05f628c7
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/style/web-2.0.css
@@ -0,0 +1,500 @@
+@charset "UTF-8";
+/* Resets and base styles from HTML5 Boilerplate */
+div, span, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
+small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after, q:before, q:after {
+ content: "";
+ content: none;
+}
+
+ins {
+ background-color: #ff9;
+ color: #000;
+ text-decoration: none;
+}
+
+mark {
+ background-color: #ff9;
+ color: #000;
+ font-style: italic;
+ font-weight: bold;
+}
+
+del {
+ text-decoration: line-through;
+}
+
+abbr[title], dfn[title] {
+ border-bottom: 1px dotted;
+ cursor: help;
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+hr {
+ display: block;
+ height: 1px;
+ border: 0;
+ border-top: 1px solid #ccc;
+ margin: 1em 0;
+ padding: 0;
+}
+
+input, select {
+ vertical-align: middle;
+}
+
+select, input, textarea, button {
+ font: 99% sans-serif;
+}
+
+pre, code, kbd, samp {
+ font-family: monospace, sans-serif;
+}
+
+a {
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+a:hover, a:active {
+ outline: none;
+}
+
+ul, ol {
+ margin-left: 2em;
+ vertical-align: top;
+}
+
+ol {
+ list-style-type: decimal;
+}
+
+nav ul, nav li {
+ margin: 0;
+ list-style: none;
+ list-style-image: none;
+}
+
+small {
+ font-size: 85%;
+}
+
+strong, th {
+ font-weight: bold;
+}
+
+td {
+ vertical-align: top;
+}
+
+sub, sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+textarea {
+ overflow: auto;
+}
+
+input[type="radio"] {
+ vertical-align: text-bottom;
+}
+
+input[type="checkbox"] {
+ vertical-align: bottom;
+}
+
+label,
+input[type="button"],
+input[type="submit"],
+input[type="image"],
+button {
+ cursor: pointer;
+}
+
+button, input, select, textarea {
+ margin: 0;
+}
+
+input:invalid, textarea:invalid {
+ border-radius: 1px;
+ -moz-box-shadow: 0px 0px 5px red;
+ -webkit-box-shadow: 0px 0px 5px red;
+ box-shadow: 0px 0px 5px red;
+}
+input:invalid .no-boxshadow, textarea:invalid .no-boxshadow {
+ background-color: #f0dddd;
+}
+
+button {
+ width: auto;
+ overflow: visible;
+}
+
+select, input, textarea {
+ color: #444444;
+}
+
+a {
+ color: #607890;
+}
+a:hover, a:focus {
+ color: #036;
+}
+a:link {
+ -webkit-tap-highlight-color: #fff;
+}
+
+/* End HTML5 Boilerplate adaptations */
+h1 {
+ font-size: 4.5em;
+}
+
+h1, .vcenter {
+ font-weight: bold;
+ text-align: center;
+ padding-top: 1em;
+ max-height: 100%;
+}
+.csstransforms h1, .csstransforms .vcenter {
+ padding: 0 48px;
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 50%;
+ -webkit-transform: translate(0, -50%);
+ -moz-transform: translate(0, -50%);
+ -ms-transform: translate(0, -50%);
+ -o-transform: translate(0, -50%);
+ transform: translate(0, -50%);
+}
+
+.vcenter h1 {
+ position: relative;
+ top: auto;
+ padding: 0;
+ -webkit-transform: none;
+ -moz-transform: none;
+ -ms-transform: none;
+ -o-transform: none;
+ transform: none;
+}
+
+h2 {
+ font-size: 2.25em;
+ font-weight: bold;
+ padding-top: .5em;
+ margin: 0 0 .66666em 0;
+ border-bottom: 3px solid #888;
+}
+
+h3 {
+ font-size: 1.4375em;
+ font-weight: bold;
+ margin-bottom: .30435em;
+}
+
+h4 {
+ font-size: 1.25em;
+ font-weight: bold;
+ margin-bottom: .25em;
+}
+
+h5 {
+ font-size: 1.125em;
+ font-weight: bold;
+ margin-bottom: .2222em;
+}
+
+h6 {
+ font-size: 1em;
+ font-weight: bold;
+}
+
+img, iframe, video {
+ display: block;
+ max-width: 100%;
+}
+
+video, iframe, img {
+ display: block;
+ margin: 0 auto;
+}
+
+p, blockquote, iframe, img, ul, ol, pre, video {
+ margin-bottom: 1em;
+}
+
+pre {
+ white-space: pre;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ padding: 1em;
+ border: 1px solid #888;
+}
+
+em {
+ font-style: italic;
+}
+
+li {
+ padding: .25em 0;
+ vertical-align: middle;
+}
+li > ol, li > ul {
+ margin-bottom: inherit;
+}
+
+.deck-container {
+ font-size: 16px;
+ line-height: 1.25;
+ color: #444;
+}
+
+.slide {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-family: "Hoefler Text", Constantia, Palatino, "Palatino Linotype", "Book Antiqua", Georgia, serif;
+}
+
+h1 {
+ color: #08455f;
+}
+
+h2 {
+ color: #0b7495;
+ border-bottom: 0;
+}
+.cssreflections h2 {
+ line-height: 1;
+ -webkit-box-reflect: below -0.5555em -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0.3, transparent), color-stop(0.7, rgba(255, 255, 255, 0.1)), to(transparent));
+ -moz-box-reflect: below -0.5555em -moz-linear-gradient(top, transparent 0%, transparent 30%, rgba(255, 255, 255, 0.3) 100%);
+}
+
+h3 {
+ color: #000;
+}
+
+pre {
+ border-color: #cde;
+ background: #fff;
+ position: relative;
+ z-index: auto;
+ border-radius: 5px;
+ /* http://nicolasgallagher.com/css-drop-shadows-without-images/ */
+}
+.csstransforms.boxshadow pre > :first-child:before {
+ content: "";
+ position: absolute;
+ z-index: -1;
+ background: #fff;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+}
+.csstransforms.boxshadow pre:before, .csstransforms.boxshadow pre:after {
+ content: "";
+ position: absolute;
+ z-index: -2;
+ bottom: 15px;
+ width: 50%;
+ height: 20%;
+ max-width: 300px;
+ box-shadow: 0 15px 10px rgba(0, 0, 0, 0.7);
+}
+.csstransforms.boxshadow pre:before {
+ left: 10px;
+ -webkit-transform: rotate(-3deg);
+ -ms-transform: rotate(-3deg);
+ transform: rotate(-3deg);
+}
+.csstransforms.boxshadow pre:after {
+ right: 10px;
+ -webkit-transform: rotate(3deg);
+ -ms-transform: rotate(3deg);
+ transform: rotate(3deg);
+}
+
+code {
+ color: #789;
+}
+
+blockquote {
+ font-family: "Hoefler Text", Constantia, Palatino, "Palatino Linotype", "Book Antiqua", Georgia, serif;
+ font-size: 2em;
+ padding: 1em 2em .5em 2em;
+ color: #000;
+ background: #fff;
+ position: relative;
+ border: 1px solid #cde;
+ z-index: auto;
+ border-radius: 5px;
+}
+.boxshadow blockquote > :first-child:before {
+ content: "";
+ position: absolute;
+ z-index: -1;
+ background: #fff;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+}
+.boxshadow blockquote:after {
+ content: "";
+ position: absolute;
+ z-index: -2;
+ top: 10px;
+ bottom: 10px;
+ left: 0;
+ right: 50%;
+ -moz-border-radius: 10px / 100px;
+ border-radius: 10px / 100px;
+ box-shadow: 0 0 15px rgba(0, 0, 0, 0.6);
+}
+blockquote p {
+ margin: 0;
+}
+blockquote cite {
+ font-size: .5em;
+ font-style: normal;
+ font-weight: bold;
+ color: #888;
+}
+blockquote:before {
+ content: "“";
+ position: absolute;
+ top: 0;
+ left: 0;
+ font-size: 5em;
+ line-height: 1;
+ color: #ccf0f0;
+ z-index: 1;
+}
+
+::-moz-selection {
+ background: #08455f;
+ color: #fff;
+}
+
+::selection {
+ background: #08455f;
+ color: #fff;
+}
+
+a, a:hover, a:focus, a:active, a:visited {
+ color: #599;
+ text-decoration: none;
+}
+a:hover, a:focus {
+ text-decoration: underline;
+}
+
+.deck-container {
+ font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
+ font-size: 1.75em;
+ background: #f4fafe;
+ /* Old browsers */
+ background: -moz-linear-gradient(top, #f4fafe 0%, #ccf0f0 100%);
+ /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f4fafe), color-stop(100%, #ccf0f0));
+ /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #f4fafe 0%, #ccf0f0 100%);
+ /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #f4fafe 0%, #ccf0f0 100%);
+ /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #f4fafe 0%, #ccf0f0 100%);
+ /* IE10+ */
+ background: linear-gradient(top, #f4fafe 0%, #ccf0f0 100%);
+ /* W3C */
+ background-attachment: fixed;
+ text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.5);
+}
+.deck-container > .slide {
+ padding: 0 48px;
+}
+
+.slide .deck-before, .slide .deck-previous {
+ opacity: 0.4;
+}
+.slide .deck-before:not(.deck-child-current) .deck-before, .slide .deck-before:not(.deck-child-current) .deck-previous, .slide .deck-previous:not(.deck-child-current) .deck-before, .slide .deck-previous:not(.deck-child-current) .deck-previous {
+ opacity: 1;
+}
+.slide .deck-child-current {
+ opacity: 1;
+}
+
+.deck-prev-link, .deck-next-link {
+ background: #fff;
+ opacity: 0.5;
+}
+.deck-prev-link, .deck-prev-link:hover, .deck-prev-link:focus, .deck-prev-link:active, .deck-prev-link:visited, .deck-next-link, .deck-next-link:hover, .deck-next-link:focus, .deck-next-link:active, .deck-next-link:visited {
+ color: #599;
+}
+.deck-prev-link:hover, .deck-prev-link:focus, .deck-next-link:hover, .deck-next-link:focus {
+ opacity: 1;
+ text-decoration: none;
+}
+
+.deck-status {
+ font-size: 0.6666em;
+}
+
+.deck-menu .slide {
+ background: transparent;
+ border-radius: 5px;
+}
+.rgba .deck-menu .slide {
+ background: rgba(0, 0, 0, 0.1);
+}
+.deck-menu .slide.deck-current, .rgba .deck-menu .slide.deck-current, .no-touch .deck-menu .slide:hover {
+ background: #fff;
+}
+
+.goto-form {
+ background: #fff;
+ border: 1px solid #cde;
+ border-radius: 5px;
+}
+.boxshadow .goto-form {
+ box-shadow: 0 15px 10px -10px rgba(0, 0, 0, 0.5), 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
+}
diff --git a/doc/backends/deckjs/deck.js/themes/style/web-2.0.scss b/doc/backends/deckjs/deck.js/themes/style/web-2.0.scss
new file mode 100644
index 00000000..aa9e9b0a
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/style/web-2.0.scss
@@ -0,0 +1,228 @@
+@mixin rotate($deg) {
+ -webkit-transform:rotate($deg);
+ -ms-transform:rotate($deg);
+ transform:rotate($deg);
+}
+
+@import "reset";
+
+h1, h2, h3, h4, h5, h6 {
+ font-family: "Hoefler Text", Constantia, Palatino, "Palatino Linotype", "Book Antiqua", Georgia, serif;
+}
+
+h1 {
+ color:#08455f;
+}
+
+h2 {
+ color:#0b7495;
+ border-bottom:0;
+
+ .cssreflections & {
+ line-height:1;
+ -webkit-box-reflect:below -0.5555em -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0.3, transparent), color-stop(0.7, rgba(255,255,255,.1)), to(transparent));
+ -moz-box-reflect:below -0.5555em -moz-linear-gradient(top, transparent 0%, transparent 30%, rgba(255,255,255,.3) 100%);
+ }
+}
+
+h3 {
+ color:#000;
+}
+
+pre {
+ border-color:#cde;
+ background:#fff;
+ position:relative;
+ z-index:auto;
+ border-radius:5px;
+
+ /* http://nicolasgallagher.com/css-drop-shadows-without-images/ */
+ .csstransforms.boxshadow & {
+ > :first-child:before {
+ content:"";
+ position:absolute;
+ z-index:-1;
+ background:#fff;
+ top:0;
+ bottom:0;
+ left:0;
+ right:0;
+ }
+
+ &:before, &:after {
+ content:"";
+ position:absolute;
+ z-index:-2;
+ bottom:15px;
+ width:50%;
+ height:20%;
+ max-width:300px;
+ box-shadow:0 15px 10px rgba(0, 0, 0, 0.7);
+ }
+
+ &:before {
+ left:10px;
+ @include rotate(-3deg);
+ }
+
+ &:after {
+ right:10px;
+ @include rotate(3deg);
+ }
+ }
+}
+
+code {
+ color:#789;
+}
+
+blockquote {
+ font-family: "Hoefler Text", Constantia, Palatino, "Palatino Linotype", "Book Antiqua", Georgia, serif;
+ font-size:2em;
+ padding:1em 2em .5em 2em;
+ color:#000;
+ background:#fff;
+ position:relative;
+ border:1px solid #cde;
+ z-index:auto;
+ border-radius:5px;
+
+ .boxshadow & {
+ > :first-child:before {
+ content:"";
+ position:absolute;
+ z-index:-1;
+ background:#fff;
+ top:0;
+ bottom:0;
+ left:0;
+ right:0;
+ }
+
+ &:after {
+ content:"";
+ position:absolute;
+ z-index:-2;
+ top: 10px;
+ bottom: 10px;
+ left: 0;
+ right: 50%;
+ -moz-border-radius: 10px / 100px;
+ border-radius: 10px / 100px;
+ box-shadow:0 0 15px rgba(0,0,0,0.6);
+ }
+ }
+
+ p {
+ margin:0;
+ }
+
+ cite {
+ font-size:.5em;
+ font-style:normal;
+ font-weight:bold;
+ color:#888;
+ }
+
+ &:before {
+ content:"“";
+ position:absolute;
+ top:0;
+ left:0;
+ font-size:5em;
+ line-height:1;
+ color:#ccf0f0;
+ z-index:1;
+ }
+}
+
+::-moz-selection{ background:#08455f; color:#fff; }
+::selection { background:#08455f; color:#fff; }
+
+a {
+ &, &:hover, &:focus, &:active, &:visited {
+ color:#599;
+ text-decoration:none;
+ }
+
+ &:hover, &:focus {
+ text-decoration:underline;
+ }
+}
+
+.deck-container {
+ font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
+ font-size:1.75em;
+ background: rgb(244,250,254); /* Old browsers */
+ background: -moz-linear-gradient(top, rgba(244,250,254,1) 0%, rgba(204,240,240,1) 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(244,250,254,1)), color-stop(100%,rgba(204,240,240,1))); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, rgba(244,250,254,1) 0%,rgba(204,240,240,1) 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, rgba(244,250,254,1) 0%,rgba(204,240,240,1) 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, rgba(244,250,254,1) 0%,rgba(204,240,240,1) 100%); /* IE10+ */
+ background: linear-gradient(top, rgba(244,250,254,1) 0%,rgba(204,240,240,1) 100%); /* W3C */
+ background-attachment: fixed;
+ text-shadow:1px 1px 1px rgba(255,255,255,.5);
+
+ > .slide {
+ padding:0 48px;
+ }
+}
+
+.slide {
+ .deck-before, .deck-previous {
+ opacity:0.4;
+
+ &:not(.deck-child-current) {
+ .deck-before, .deck-previous {
+ opacity:1;
+ }
+ }
+ }
+
+ .deck-child-current {
+ opacity:1;
+ }
+}
+
+.deck-prev-link, .deck-next-link {
+ background:#fff;
+ opacity:0.5;
+
+ &, &:hover, &:focus, &:active, &:visited {
+ color:#599;
+ }
+
+ &:hover, &:focus {
+ opacity:1;
+ text-decoration:none;
+ }
+}
+
+.deck-status {
+ font-size:0.6666em;
+}
+
+.deck-menu {
+ .slide {
+ background:transparent;
+ border-radius:5px;
+
+ .rgba & {
+ background:rgba(0,0,0,.1);
+ }
+
+ &.deck-current, .rgba &.deck-current, .no-touch &:hover {
+ background:#fff;
+ }
+ }
+}
+
+.goto-form {
+ background:#fff;
+ border:1px solid #cde;
+ border-radius:5px;
+
+ .boxshadow & {
+ box-shadow: 0 15px 10px -10px rgba(0, 0, 0, 0.5), 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
+ }
+} \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/themes/transition/beamer.css b/doc/backends/deckjs/deck.js/themes/transition/beamer.css
new file mode 100644
index 00000000..f6b06a38
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/transition/beamer.css
@@ -0,0 +1,66 @@
+.csstransitions.csstransforms {
+ overflow-x: hidden; }
+ .csstransitions.csstransforms .deck-container .slide {
+ -webkit-transition: -webkit-transform 500ms ease-in-out;
+ -moz-transition: -moz-transform 500ms ease-in-out;
+ -ms-transition: -ms-transform 500ms ease-in-out;
+ -o-transition: -o-transform 500ms ease-in-out;
+ transition: transform 500ms ease-in-out; }
+ .csstransitions.csstransforms .deck-container:not(.deck-menu) .slide {
+ position: absolute;
+ top: 0;
+ left: 0;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%; }
+ .csstransitions.csstransforms .deck-container:not(.deck-menu) .slide .slide {
+ position: relative;
+ left: 0;
+ top: 0;
+ -webkit-transition: -webkit-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ -moz-transition: -moz-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ -ms-transition: -ms-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ -o-transition: -o-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ transition: -webkit-transform 500ms ease-in-out, opacity 500ms ease-in-out; }
+ .csstransitions.csstransforms .deck-container:not(.deck-menu) .slide .deck-next, .csstransitions.csstransforms .deck-container:not(.deck-menu) .slide .deck-after {
+ visibility: visible;
+ -webkit-transform: translate3d(200%, 0, 0);
+ -moz-transform: translate(200%, 0);
+ -ms-transform: translate(200%, 0);
+ -o-transform: translate(200%, 0);
+ transform: translate3d(200%, 0, 0); }
+ .csstransitions.csstransforms .deck-container:not(.deck-menu) .slide .deck-before, .csstransitions.csstransforms .deck-container:not(.deck-menu) .slide .deck-previous {
+ opacity: 0.4; }
+ .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-previous {
+ -webkit-transform: translate3d(-200%, 0, 0);
+ -moz-transform: translate(-200%, 0);
+ -ms-transform: translate(-200%, 0);
+ -o-transform: translate(-200%, 0);
+ transform: translate3d(-200%, 0, 0); }
+ .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-before {
+ -webkit-transform: translate3d(-400%, 0, 0);
+ -moz-transform: translate(-400%, 0);
+ -ms-transform: translate(-400%, 0);
+ -o-transform: translate(-400%, 0);
+ transform: translate3d(-400%, 0, 0); }
+ .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-next {
+ -webkit-transform: translate3d(200%, 0, 0);
+ -moz-transform: translate(200%, 0);
+ -ms-transform: translate(200%, 0);
+ -o-transform: translate(200%, 0);
+ transform: translate3d(200%, 0, 0); }
+ .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-after {
+ -webkit-transform: translate3d(400%, 0, 0);
+ -moz-transform: translate(400%, 0);
+ -ms-transform: translate(400%, 0);
+ -o-transform: translate(400%, 0);
+ transform: translate3d(400%, 0, 0); }
+ .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-before .slide, .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-previous .slide {
+ visibility: visible; }
+ .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-child-current {
+ -webkit-transform: none;
+ -moz-transform: none;
+ -ms-transform: none;
+ -o-transform: none;
+ transform: none; }
diff --git a/doc/backends/deckjs/deck.js/themes/transition/beamer.scss b/doc/backends/deckjs/deck.js/themes/transition/beamer.scss
new file mode 100644
index 00000000..b6408d0d
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/transition/beamer.scss
@@ -0,0 +1,95 @@
+@mixin translate($x: 0, $y: 0, $z: 0) {
+ -webkit-transform:translate3d($x, $y, $z);
+ -moz-transform:translate($x, $y);
+ -ms-transform:translate($x, $y);
+ -o-transform:translate($x, $y);
+ transform:translate3d($x, $y, $z);
+}
+
+@mixin transition($prop, $duration, $easing: ease-in-out, $delay: 0ms) {
+ -webkit-transition:$prop $duration $easing $delay;
+ -moz-transition:$prop $duration $easing $delay;
+ -ms-transition:$prop $duration $easing $delay;
+ -o-transition:$prop $duration $easing $delay;
+ transition:$prop $duration $easing $delay;
+}
+
+@mixin transform($val) {
+ -webkit-transform:$val;
+ -moz-transform:$val;
+ -ms-transform:$val;
+ -o-transform:$val;
+ transform:$val;
+}
+
+.csstransitions.csstransforms {
+ overflow-x:hidden;
+
+ .deck-container .slide {
+ -webkit-transition:-webkit-transform 500ms ease-in-out;
+ -moz-transition:-moz-transform 500ms ease-in-out;
+ -ms-transition:-ms-transform 500ms ease-in-out;
+ -o-transition:-o-transform 500ms ease-in-out;
+ transition:transform 500ms ease-in-out;
+ }
+
+ .deck-container:not(.deck-menu) {
+ .slide {
+ position: absolute;
+ top:0;
+ left:0;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+ //padding:24px 24px;
+
+ .slide {
+
+ position:relative;
+ left: 0;
+ top: 0;
+ -webkit-transition: -webkit-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ -moz-transition: -moz-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ -ms-transition: -ms-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ -o-transition: -o-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ transition: -webkit-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ }
+
+ .deck-next, .deck-after {
+ visibility: visible;
+ @include translate(200%);
+ }
+
+ .deck-before, .deck-previous {
+ opacity:0.4;
+ }
+ }
+
+ > .deck-previous {
+ @include translate(-200%);
+ }
+
+ > .deck-before {
+ @include translate(-400%);
+ }
+
+ > .deck-next {
+ @include translate(200%);
+ }
+
+ > .deck-after {
+ @include translate(400%);
+ }
+
+ > .deck-before, > .deck-previous {
+ .slide {
+ visibility:visible;
+ }
+ }
+
+ > .deck-child-current {
+ @include transform(none);
+ }
+ }
+} \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/themes/transition/fade.css b/doc/backends/deckjs/deck.js/themes/transition/fade.css
new file mode 100644
index 00000000..ad5338cf
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/transition/fade.css
@@ -0,0 +1,35 @@
+.csstransitions.csstransforms .deck-container .slide {
+ -webkit-transition: opacity 500ms ease-in-out 0ms;
+ transition: opacity 500ms ease-in-out 0ms;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide {
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide .slide {
+ position: relative;
+ left: 0;
+ top: 0;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide .deck-next, .csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide .deck-after {
+ opacity: 0;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide .deck-current {
+ opacity: 1;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-previous, .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-before, .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-next, .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-after {
+ opacity: 0;
+ pointer-events: none;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-before .slide, .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-previous .slide {
+ visibility: visible;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-child-current {
+ opacity: 1;
+ visibility: visible;
+ pointer-events: auto;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-child-current .deck-next, .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-child-current .deck-after {
+ visibility: hidden;
+}
diff --git a/doc/backends/deckjs/deck.js/themes/transition/fade.scss b/doc/backends/deckjs/deck.js/themes/transition/fade.scss
new file mode 100644
index 00000000..56fbd4c5
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/transition/fade.scss
@@ -0,0 +1,59 @@
+@mixin translate($x: 0, $y: 0, $z: 0) {
+ -webkit-transform:translate3d($x, $y, $z);
+ -ms-transform:translate($x, $y);
+ transform:translate3d($x, $y, $z);
+}
+
+@mixin transition($prop, $duration, $easing: ease-in-out, $delay: 0ms) {
+ -webkit-transition:$prop $duration $easing $delay;
+ transition:$prop $duration $easing $delay;
+}
+
+.csstransitions.csstransforms {
+ .deck-container .slide {
+ @include transition(opacity, 500ms);
+ }
+
+ .deck-container:not(.deck-menu) {
+ > .slide {
+ position:absolute;
+ top:0;
+ left:0;
+
+ .slide {
+ position:relative;
+ left:0;
+ top:0;
+ }
+
+ .deck-next, .deck-after {
+ opacity:0;
+ }
+
+ .deck-current {
+ opacity:1;
+ }
+ }
+
+ > .deck-previous, > .deck-before, > .deck-next, > .deck-after {
+ opacity:0;
+ pointer-events:none;
+ }
+
+ > .deck-before, > .deck-previous {
+ .slide {
+ visibility:visible;
+ }
+ }
+
+ > .deck-child-current {
+ opacity:1;
+ visibility:visible;
+ pointer-events:auto;
+
+ .deck-next, .deck-after {
+ visibility:hidden;
+ }
+ }
+ }
+}
diff --git a/doc/backends/deckjs/deck.js/themes/transition/horizontal-slide.css b/doc/backends/deckjs/deck.js/themes/transition/horizontal-slide.css
new file mode 100644
index 00000000..183f030c
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/transition/horizontal-slide.css
@@ -0,0 +1,53 @@
+.csstransitions.csstransforms {
+ overflow-x: hidden;
+}
+.csstransitions.csstransforms .deck-container > .slide {
+ -webkit-transition: -webkit-transform 500ms ease-in-out;
+ transition: transform 500ms ease-in-out;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide {
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide .slide {
+ position: relative;
+ left: 0;
+ top: 0;
+ -webkit-transition: -webkit-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ transition: transform 500ms ease-in-out, opacity 500ms ease-in-out;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide .deck-next, .csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide .deck-after {
+ visibility: visible;
+ -webkit-transform: translate3d(200%, 0, 0);
+ -ms-transform: translate(200%, 0);
+ transform: translate3d(200%, 0, 0);
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-previous {
+ -webkit-transform: translate3d(-200%, 0, 0);
+ -ms-transform: translate(-200%, 0);
+ transform: translate3d(-200%, 0, 0);
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-before {
+ -webkit-transform: translate3d(-400%, 0, 0);
+ -ms-transform: translate(-400%, 0);
+ transform: translate3d(-400%, 0, 0);
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-next {
+ -webkit-transform: translate3d(200%, 0, 0);
+ -ms-transform: translate(200%, 0);
+ transform: translate3d(200%, 0, 0);
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-after {
+ -webkit-transform: translate3d(400%, 0, 0);
+ -ms-transform: translate(400%, 0);
+ transform: translate3d(400%, 0, 0);
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-before .slide, .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-previous .slide {
+ visibility: visible;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-child-current {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+}
diff --git a/doc/backends/deckjs/deck.js/themes/transition/horizontal-slide.scss b/doc/backends/deckjs/deck.js/themes/transition/horizontal-slide.scss
new file mode 100644
index 00000000..d24f8ed0
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/transition/horizontal-slide.scss
@@ -0,0 +1,72 @@
+@mixin translate($x: 0, $y: 0, $z: 0) {
+ -webkit-transform:translate3d($x, $y, $z);
+ -ms-transform:translate($x, $y);
+ transform:translate3d($x, $y, $z);
+}
+
+@mixin transition($prop, $duration, $easing: ease-in-out, $delay: 0ms) {
+ -webkit-transition:$prop $duration $easing $delay;
+ transition:$prop $duration $easing $delay;
+}
+
+@mixin transform($val) {
+ -webkit-transform:$val;
+ -ms-transform:$val;
+ transform:$val;
+}
+
+.csstransitions.csstransforms {
+ overflow-x:hidden;
+
+ .deck-container > .slide {
+ -webkit-transition:-webkit-transform 500ms ease-in-out;
+ transition:transform 500ms ease-in-out;
+ }
+
+ .deck-container:not(.deck-menu) {
+ > .slide {
+ position:absolute;
+ top:0;
+ left:0;
+
+ .slide {
+ position:relative;
+ left:0;
+ top:0;
+ -webkit-transition:-webkit-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ transition:transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ }
+
+ .deck-next, .deck-after {
+ visibility:visible;
+ @include translate(200%);
+ }
+ }
+
+ > .deck-previous {
+ @include translate(-200%);
+ }
+
+ > .deck-before {
+ @include translate(-400%);
+ }
+
+ > .deck-next {
+ @include translate(200%);
+ }
+
+ > .deck-after {
+ @include translate(400%);
+ }
+
+ > .deck-before, > .deck-previous {
+ .slide {
+ visibility:visible;
+ }
+ }
+
+ > .deck-child-current {
+ @include transform(none);
+ }
+ }
+} \ No newline at end of file
diff --git a/doc/backends/deckjs/deck.js/themes/transition/vertical-slide.css b/doc/backends/deckjs/deck.js/themes/transition/vertical-slide.css
new file mode 100644
index 00000000..b8ec020a
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/transition/vertical-slide.css
@@ -0,0 +1,67 @@
+.csstransitions.csstransforms .deck-container {
+ overflow-y: hidden;
+}
+.csstransitions.csstransforms .deck-container > .slide {
+ -webkit-transition: -webkit-transform 500ms ease-in-out;
+ transition: transform 500ms ease-in-out;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide {
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide .slide {
+ position: relative;
+ left: 0;
+ top: 0;
+ -webkit-transition: -webkit-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ transition: transform 500ms ease-in-out, opacity 500ms ease-in-out;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide .deck-next, .csstransitions.csstransforms .deck-container:not(.deck-menu) > .slide .deck-after {
+ visibility: visible;
+ -webkit-transform: translate3d(0, 1600px, 0);
+ -ms-transform: translate(0, 1600px);
+ transform: translate3d(0, 1600px, 0);
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-previous {
+ -webkit-transform: translate3d(0, -200%, 0);
+ -ms-transform: translate(0, -200%);
+ transform: translate3d(0, -200%, 0);
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-before {
+ -webkit-transform: translate3d(0, -400%, 0);
+ -ms-transform: translate(0, -400%);
+ transform: translate3d(0, -400%, 0);
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-next {
+ -webkit-transform: translate3d(0, 200%, 0);
+ -ms-transform: translate(0, 200%);
+ transform: translate3d(0, 200%, 0);
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-after {
+ -webkit-transform: translate3d(0, 400%, 0);
+ -ms-transform: translate(0, 400%);
+ transform: translate3d(0, 400%, 0);
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-before .slide, .csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-previous .slide {
+ visibility: visible;
+}
+.csstransitions.csstransforms .deck-container:not(.deck-menu) > .deck-child-current {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+}
+.csstransitions.csstransforms .deck-prev-link {
+ left: auto;
+ right: 8px;
+ top: 59px;
+ -webkit-transform: rotate(90deg);
+ -ms-transform: rotate(90deg);
+ transform: rotate(90deg);
+}
+.csstransitions.csstransforms .deck-next-link {
+ top: 99px;
+ -webkit-transform: rotate(90deg);
+ -ms-transform: rotate(90deg);
+ transform: rotate(90deg);
+}
diff --git a/doc/backends/deckjs/deck.js/themes/transition/vertical-slide.scss b/doc/backends/deckjs/deck.js/themes/transition/vertical-slide.scss
new file mode 100644
index 00000000..2187725c
--- /dev/null
+++ b/doc/backends/deckjs/deck.js/themes/transition/vertical-slide.scss
@@ -0,0 +1,92 @@
+@mixin translate($x: 0, $y: 0, $z: 0) {
+ -webkit-transform:translate3d($x, $y, $z);
+ -ms-transform:translate($x, $y);
+ transform:translate3d($x, $y, $z);
+}
+
+@mixin rotate($deg) {
+ -webkit-transform:rotate($deg);
+ -ms-transform:rotate($deg);
+ transform:rotate($deg);
+}
+
+@mixin transition($prop, $duration, $easing: ease-in-out, $delay: 0ms) {
+ -webkit-transition:$prop $duration $easing $delay;
+ transition:$prop $duration $easing $delay;
+}
+
+@mixin transform($val) {
+ -webkit-transform:$val;
+ -ms-transform:$val;
+ transform:$val;
+}
+
+.csstransitions.csstransforms {
+ .deck-container {
+ overflow-y:hidden;
+
+ > .slide {
+ -webkit-transition:-webkit-transform 500ms ease-in-out;
+ transition:transform 500ms ease-in-out;
+ }
+ }
+
+ .deck-container:not(.deck-menu) {
+ > .slide {
+ position:absolute;
+ top:0;
+ left:0;
+
+ .slide {
+ position:relative;
+ left:0;
+ top:0;
+ -webkit-transition:-webkit-transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ transition:transform 500ms ease-in-out, opacity 500ms ease-in-out;
+ }
+
+ .deck-next, .deck-after {
+ visibility:visible;
+ @include translate(0, 1600px);
+ }
+ }
+
+ > .deck-previous {
+ @include translate(0, -200%);
+ }
+
+ > .deck-before {
+ @include translate(0, -400%);
+ }
+
+ > .deck-next {
+ @include translate(0, 200%);
+ }
+
+ > .deck-after {
+ @include translate(0, 400%);
+ }
+
+ > .deck-before, > .deck-previous {
+ .slide {
+ visibility:visible;
+ }
+ }
+
+ > .deck-child-current {
+ @include transform(none);
+ }
+ }
+
+ .deck-prev-link {
+ left:auto;
+ right:8px;
+ top:59px;
+ @include rotate(90deg);
+ }
+
+ .deck-next-link {
+ top:99px;
+ @include rotate(90deg);
+ }
+} \ No newline at end of file
diff --git a/doc/backends/deckjs/deckjs.conf b/doc/backends/deckjs/deckjs.conf
new file mode 100644
index 00000000..95573359
--- /dev/null
+++ b/doc/backends/deckjs/deckjs.conf
@@ -0,0 +1,335 @@
+# version 1.6.3
+
+include::{asciidoc-confdir}/xhtml11.conf[]
+:backend-deckjs:
+
+[miscellaneous]
+outfilesuffix=.html
+
+[attributes]
+basebackend=html
+basebackend-html=
+backend-deckjs=
+
+[macros]
+(?u)^(?P<name>video)::(?P<target>\S*?)(\[(?P<attrlist>.*?)\])$=#
+
+^>{3,}$=#nopagebreak
+
+[preamble]
+
+[sect1]
+<section class="slide">
+<h2>{title}</h2>
+|
+</section>
+
+[paragraph]
+<p>
+|
+</p>
+
+
+#------------------------
+#strike trough style
+[quotes]
+-=strikethrough
+
+[tags]
+strikethrough=<span style="text-decoration: line-through;">|</span>
+
+
+#------------------------
+#for literal block incremental
+
+[literalblock]
+<div class="literalblock{role? {role}}{incremental-option? slide}{incremental? slide}"{id? id="{id}"}>
+<div class="title">{title}</div>
+<div class="content">
+<pre><tt>
+|
+</tt></pre>
+</div></div>
+
+
+#------------------------
+# for quote block
+
+[blockdef-quote]
+delimiter=^_{4,}$
+quote-style=template="quote_block",options=("a",)
+
+[quote_block]
+<blockquote class="{incremental?slide }{incremental-option?slide}">
+ <p>|</p>
+ <p><cite>-- {attribution} {citetitle?, {citetitle}}</cite></p>
+</blockquote>
+
+
+#------------------------
+# for image
+
+[image-blockmacro]
+# TODO use image block title for alt
+# <img src="{imagesdir=}{imagesdir?/}{target}" alt="{alt={target}}" class="{incremental-option?slide }{incremental?slide}"/>
+<div class="imageblock{style? {style}}{role? {role}}{unbreakable-option? unbreakable}{incremental-option? slide}{incremental? slide}"{id? id="{id}"}{align? style="text-align:{align};"}{float? style="float:{float};"}>
+<div class="content">
+<a class="image" href="{link}">
+{data-uri%}<img src="{imagesdir=}{imagesdir?/}{target}" alt="{alt={target}}"{width? width="{width}"}{height? height="{height}"}>
+{data-uri#}<img alt="{alt={target}}"{width? width="{width}"}{height? height="{height}"} src="data:image/{eval:os.path.splitext(r'{target}')[1][1:]};base64,
+{data-uri#}{sys:"{python}" -u -c "import base64,sys; base64.encode(sys.stdin,sys.stdout)" < "{eval:os.path.join(r"{indir={outdir}}",r"{imagesdir=}",r"{target}")}"}">
+{link#}</a>
+</div>
+<div class="title" style="text-align: center">{caption={figure-caption} {counter:figure-number}. }{title}</div>
+</div>
+
+
+#------------------------
+# for video
+
+[video-blockmacro]
+<div class="{incremental-option?slide }{incremental?slide }">
+<iframe width="{width}" height="{height}" src="{target}" frameborder="0" allowfullscreen></iframe>
+</div>
+
+
+#------------------------
+# for lists
+
+[listtags-bulleted]
+list=<ul>|</ul>
+item=<li class="{incremental-option?slide}{incremental? slide}">|</li>
+text=
+
+[listtags-numbered]
+list=<ol>|</ol>
+item=<li class="{incremental-option?slide}{incremental? slide}">|</li>
+text=<p>|</p>
+
+
+#------------------------
+# for source code block incremental
+[listingblock]
+<div class="listingblock{role? {role}}{incremental-option? slide}{incremental? slide}"{id? id="{id}"}>
+<div class="title">{caption=}{title}</div>
+<div class="content">
+<pre><tt>
+|
+</tt></pre>
+</div></div>
+
+[source-highlight-block]
+<div class="listingblock{incremental-option? slide}{incremental? slide}">
+<a id="{id}"></a>
+<div class="title">{caption=}{title}</div>
+<div class="content">
+|
+</div></div>
+
+#------------------------
+# for page break improvements. See slidy2 configuration file
+[nopagebreak-blockmacro]
+{set:slidepagebreak!}
+
+[pagebreak-blockmacro]
+</div></div></div></div><div style="page-break-after:always">
+{slidepagebreak}</div>
+{set:slidepagebreak}
+
+
+[header]
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <title>{doctitle=}</title>
+ <meta name="description" content="{description}" />
+ <meta name="viewport" content="width=1024, user-scalable=no">
+ <meta name="author" content="{author}" />
+ <meta name="generator" content="AsciiDoc {asciidoc-version}" />
+ <meta name="presdate" content="{revdate}" />
+ {corpname?<meta name="company" content="{corpname}" />}
+ <!-- Core and extension CSS files -->
+ifdef::linkcss[]
+ <link rel="stylesheet" href="deck.js/core/deck.core.css">
+ <link rel="stylesheet" href="deck.js/extensions/goto/deck.goto.css">
+ <link rel="stylesheet" href="deck.js/extensions/menu/deck.menu.css">
+ <link rel="stylesheet" href="deck.js/extensions/navigation/deck.navigation.css">
+ <link rel="stylesheet" href="deck.js/extensions/status/deck.status.css">
+ <link rel="stylesheet" href="deck.js/extensions/toc/deck.toc.css">
+ <!-- Theme CSS files -->
+ <link rel="stylesheet" href="./deck.js/themes/style/{deckjs_theme}.css">
+ <link rel="stylesheet" href="./deck.js/themes/transition/{deckjs_transition}.css">
+ {pygments?<link rel="stylesheet" href="./ad-stylesheet/pygments/{pygments_style}.css">}
+ <!-- Replace path with correct path to Modernizr file. -->
+ <script src="deck.js/modernizr.custom.js"></script>
+endif::linkcss[]
+ifndef::linkcss[]
+<style type="text/css">
+include1::{stylesdir=./deck.js/core}/deck.core.css[]
+</style>
+<style type="text/css">
+include1::{stylesdir=./deck.js/extensions/goto}/deck.goto.css[]
+</style>
+<style type="text/css">
+include1::{stylesdir=./deck.js/extensions/menu}/deck.menu.css[]
+</style>
+<style type="text/css">
+include1::{stylesdir=./deck.js/extensions/navigation}/deck.navigation.css[]
+</style>
+<style type="text/css">
+include1::{stylesdir=./deck.js/extensions/status}/deck.status.css[]
+</style>
+<style type="text/css">
+include1::{stylesdir=./deck.js/extensions/toc}/deck.toc.css[]
+</style>
+<style type="text/css">
+include1::{stylesdir=./deck.js/extensions/scale}/deck.scale.css[]
+</style>
+<!-- Theme CSS files -->
+<style type="text/css">
+include1::{stylesdir=./deck.js/themes/style}/{deckjs_theme}.css[]
+</style>
+<style type="text/css" id="transition-theme-link">
+include1::{stylesdir=./deck.js/themes/transition}/{deckjs_transition}.css[]
+</style>
+ifdef::pygments[]
+<style type="text/css">
+include1::{stylesdir=./ad-stylesheet/pygments}/{pygments_style}.css[]
+</style>
+endif::pygments[]
+<!-- Replace path with correct path to Modernizr file. -->
+<script type="text/javascript">
+# Escape as CDATA to pass validators.
+/*<![CDATA[*/
+include1::{scriptsdir=./deck.js}/modernizr.custom.js[]
+/*]]>*/
+</script>
+<script type="text/javascript">
+/*<![CDATA[*/
+include1::{scriptsdir=./deck.js}/jquery.min.js[]
+/*]]>*/
+</script>
+<!-- Deck Core and extensions -->
+<script type="text/javascript">
+/*<![CDATA[*/
+include1::{scriptsdir=./deck.js/core}/deck.core.js[]
+/*]]>*/
+</script>
+<script type="text/javascript">
+/*<![CDATA[*/
+include1::{scriptsdir=./deck.js/extensions/menu}/deck.menu.js[]
+/*]]>*/
+</script>
+<script type="text/javascript">
+/*<![CDATA[*/
+include1::{scriptsdir=./deck.js/extensions/goto}/deck.goto.js[]
+/*]]>*/
+</script>
+<script type="text/javascript">
+/*<![CDATA[*/
+include1::{scriptsdir=./deck.js/extensions/status}/deck.status.js[]
+/*]]>*/
+</script>
+<script type="text/javascript">
+/*<![CDATA[*/
+include1::{scriptsdir=./deck.js/extensions/navigation}/deck.navigation.js[]
+/*]]>*/
+</script>
+<script type="text/javascript">
+/*<![CDATA[*/
+include1::{scriptsdir=./deck.js/extensions/toc}/deck.toc.js[]
+/*]]>*/
+</script>
+<script type="text/javascript">
+/*<![CDATA[*/
+include1::{scriptsdir=./deck.js/extensions/deck.js-blank}/deck.blank.js[]
+/*]]>*/
+</script>
+<script type="text/javascript">
+/*<![CDATA[*/
+include1::{scriptsdir=./deck.js/extensions/split}/deck.split.js[]
+/*]]>*/
+</script>
+<script type="text/javascript">
+/*<![CDATA[*/
+include1::{scriptsdir=./deck.js/extensions/scale}/deck.scale.js[]
+/*]]>*/
+</script>
+
+endif::linkcss[]
+</head>
+<body class="deck-container">
+<section class="slide" id="title-slide">
+ <h1>{doctitle}</h1>
+ <h3>{author}{corpname? — {corpname}}</h3>
+ <h4>{revdate}</h4>
+</section>
+
+
+
+[footer]
+<a href="#" class="deck-prev-link" title="Previous">&#8592;</a>
+<a href="#" class="deck-next-link" title="Next">&#8594;</a>
+<p class="deck-status">
+ <span class="deck-status-current"></span>
+ /
+ <span class="deck-status-total"></span>
+</p>
+# toc pannel
+<div class="deck-toc"></div>
+# toc status panel
+#<table class="deck-toc-status">
+# <tr>
+# <td class="right deck-toc-h2">&nbsp;</td>
+# <td class="left deck-toc-h3">&nbsp;</td>
+# </tr>
+#</table>
+<form action="." method="get" class="goto-form">
+ <label for="goto-slide">Go to slide:</label>
+ <input type="text" name="slidenum" id="goto-slide" list="goto-datalist">
+ <datalist id="goto-datalist"></datalist>
+ <input type="submit" value="Go">
+</form>
+<!-- Other extension HTML snippets go here, at the bottom of the deck container. -->
+ifdef::linkcss[]
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
+ <script>window.jQuery || document.write('<script src="deck.js/jquery.min.js"><\/script>')</script>
+<!-- for JQuery backward compatibility -->
+ <script>window.jQuery || document.write('<script src="deck.js/jquery.min.js"><\/script>')</script>
+ <!-- Deck Core and extensions -->
+ <script src="deck.js/core/deck.core.js"></script>
+ <script src="deck.js/extensions/menu/deck.menu.js"></script>
+ <script src="deck.js/extensions/goto/deck.goto.js"></script>
+ <script src="deck.js/extensions/status/deck.status.js"></script>
+ <script src="deck.js/extensions/navigation/deck.navigation.js"></script>
+ <script src="deck.js/extensions/toc/deck.toc.js"></script>
+ <script src="deck.js/extensions/deck.js-blank/deck.blank.js"></script>
+ <script src="deck.js/extensions/split/deck.split.js"></script>
+ <script src="deck.js/extensions/scale/deck.scale.js"></script>
+endif::linkcss[]
+<!-- Initialize the deck. You can put this in an external file if desired. -->
+<script>
+ (function($, deck, undefined) {
+
+ifdef::scrollable[]
+$.deck.defaults.keys["previous"] = [8, 33, 37, 39];
+$.deck.defaults.keys["next"] = [13, 32, 34, 39];
+endif::scrollable[]
+
+ifndef::count_nested[]
+ $.extend(true, $[deck].defaults, {
+ countNested: false
+ });
+endif::count_nested[]
+
+ $.deck('.slide');
+ })(jQuery, 'deck');
+</script>
+</body>
+</html>
+
+
+
+
diff --git a/doc/backends/deckjs/example/example-template.asciidoc b/doc/backends/deckjs/example/example-template.asciidoc
new file mode 100644
index 00000000..7875b2a1
--- /dev/null
+++ b/doc/backends/deckjs/example/example-template.asciidoc
@@ -0,0 +1,54 @@
+deck.js Support for Asciidoc
+=============================
+:author: Foo Bar
+:email: <foo@bar.org>
+:description: just a template file.
+:revdate: 2011-12-16
+:revnumber: 0.1
+///////////////////////
+ Themes that you can choose includes:
+ web-2.0, swiss, neon, beamer
+///////////////////////
+:deckjs_theme: web-2.0
+///////////////////////
+ Transitions that you can choose includes:
+ fade, horizontal-slide, vertical-slide
+///////////////////////
+:deckjs_transition: horizontal-slide
+///////////////////////
+ AsciiDoc use `source-highlight` as default highlighter.
+
+ Styles available for pygment highlighter:
+ monokai, manni, perldoc, borland, colorful, default, murphy, vs, trac,
+ tango, fruity, autumn, bw, emacs, vim, pastie, friendly, native,
+
+ Uncomment following two lines if you want to highlight your code
+ with `Pygments`.
+///////////////////////
+//:pygments:
+//:pygments_style: native
+///////////////////////
+ Uncomment following line if you want to scroll inside slides
+ with {down,up} arrow keys.
+///////////////////////
+//:scrollable:
+///////////////////////
+ Uncomment following line if you want to link css and js file
+ from outside instead of embedding them into the output file.
+///////////////////////
+//:linkcss:
+///////////////////////
+ Uncomment following line if you want to count each incremental
+ bullet as a new slide
+///////////////////////
+//:count_nested:
+
+== Slide One
+
+[incremental="true"]
+ * item 1
+ * item 2
+
+== Slide Two
+
+That's all.
diff --git a/doc/backends/deckjs/example/tutorial-slide.asciidoc b/doc/backends/deckjs/example/tutorial-slide.asciidoc
new file mode 100644
index 00000000..da317db2
--- /dev/null
+++ b/doc/backends/deckjs/example/tutorial-slide.asciidoc
@@ -0,0 +1,274 @@
+deck.js Support for Asciidoc
+=============================
+:author: Qingping Hou
+:email: <dave2008713@gmail.com>
+:description: a tutorial for writing deck.js presentation with asciidoc
+:revdate: 2014-06-30
+:revnumber: 0.9
+:deckjs_theme: neon
+:deckjs_transition: horizontal-slide
+:pygments:
+:pygments_style: native
+:scrollable:
+
+
+== What is deck.js?
+
+*deck.js* is a JavaScript library for building modern HTML presentations. *deck.js* is flexible enough to let advanced CSS and JavaScript authors craft highly customized decks, but also provides templates and themes for the HTML novice to build a standard slideshow.
+
+
+For more information, please check out its http://imakewebthings.github.com/deck.js/[project page].
+
+
+== What is deck.js backend for Asciidoc?
+
+*AsciiDoc-Deck.js* makes it possible to write deck.js slides in my favorite markup language *AsciiDoc*. To make life easier, I also bundled this backend with some thirdparty deck.js extensions:
+
+* https://github.com/barraq/deck.ext.js[deck.ext.js]
+* https://github.com/mikek70/deck.js-blank[deck.js-blank]
+* https://github.com/houqp/deck.split.js[deck.split.js]
+
+
+== How to generate deck.js with Asciidoc
+
+First, make sure you have at least asciidoc-8.6.6 installed and download this backend from the http://houqp.github.com/asciidoc-deckjs/[project page].
+
+Then install the backend:
+
+...........................................
+asciidoc --backend install deckjs-X.Y.Z.zip
+...........................................
+
+After the installation, it's just as simple as issuing following command:
+
+...........................................
+asciidoc -b deckjs file.asciidoc
+...........................................
+
+You can also use this backend without installation, please refer to https://github.com/houqp/asciidoc-deckjs/blob/master/README.md[README] for details.
+
+
+== Shortcuts
+
+Following are built-in shortcuts in deck.js:
+
+* jump to any slide by given number, `g`.
+* preview all slides, `m`.
+
+Shortcuts from deck.js's thirdparty extensions:
+
+* toggle table of content, `t`
+* toggle page blank/unblank, `b`
+
+
+== Syntax (basic)
+
+This part assumes that you are already familiar with some basic concepts in AsciiDoc.
+
+* slides are divided by *level 1* sections.
+...........................................
+== Slide1 title
+
+say whatever you want here.
+...........................................
+
+ifdef::backend-deckjs[<<<]
+
+* lists
+
+...........................................
+* entry1
+* entry2
+* entry3
+...........................................
+
+* ordered list
+
+...........................................
+1. entry1
+1. entry2
+1. entry3
+...........................................
+
+A complete guide for lists can be found at http://www.methods.co.nz/asciidoc/userguide.html#X64[this page]
+
+
+== Syntax (theming)
+
+You can choose theme and transition effect by specifying the *deckjs-theme* and *deckjs-transition* attributes:
+
+...........................................
+:deckjs_theme: neon
+:deckjs_transition: vertical-slide
+...........................................
+
+Refer to http://houqp.github.com/asciidoc-deckjs/example-template.asciidoc[boilerplate] for all the supported themes.
+
+
+== Syntax (nested slide)
+
+Nested slide (or subslide) give you the ability to create substeps in slides. In this backend, elements that given *incremental* attribute will be paused before show up.
+
+syntax:
+
+...........................................
+[incremental="true"]
+* this entry should show up first
+* this entry should show up following the first one
+* this entry should be the last one
+...........................................
+
+effect:
+
+[incremental="true"]
+* this entry should show up first
+* this entry should show up following the first one
+* this entry should be the last one
+
+
+== Syntax (literal block)
+syntax:
+
+ ...........................................
+ <html>
+ <head>
+ </head>
+ <body>
+ <p>Hello World.</p>
+ </body>
+ </html>
+ ...........................................
+
+effect:
+
+[incremental="true"]
+...........................................
+<html>
+ <head>
+ </head>
+ <body>
+ <p>Hello World.</p>
+ </body>
+</html>
+...........................................
+
+
+== Syntax (code block)
+
+syntax:
+
+...........................................
+[source,c,numbered]
+-------------------------------------------
+int swallow_redpill () {
+ unsigned char m[2+4], rpill[] = "\x0f\x01\x0d\x00\x00\x00\x00\xc3";
+ *((unsigned*)&rpill[3]) = (unsigned)m;
+ ((void(*)())&rpill)();
+ return (m[5]>0xd0) ? 1 : 0;
+}
+-------------------------------------------
+...........................................
+
+effect:
+
+[incremental="true"]
+[source,c,numbered]
+-------------------------------------------
+int swallow_redpill () {
+ unsigned char m[2+4], rpill[] = "\x0f\x01\x0d\x00\x00\x00\x00\xc3";
+ *((unsigned*)&rpill[3]) = (unsigned)m;
+ ((void(*)())&rpill)();
+ return (m[5]>0xd0) ? 1 : 0;
+}
+-------------------------------------------
+
+By default, AsciiDoc use *source-highlight* to highlight your code. If you want to use *Pygments*, you have to set _pygments_ attribute (refer to example template).
+
+
+== Syntax (quote block)
+QuoteBlocks syntax from Asciidoc is fully supported, you can find complete guide on http://www.methods.co.nz/asciidoc/userguide.html#_quote_blocks[this page].
+
+syntax:
+
+...........................................
+ [quote, L. Kronecker]
+ ___________________________________________
+ God made the natural number and all the rest is the work of man
+ ___________________________________________
+...........................................
+
+effect:
+
+[incremental="true"]
+[quote, L. Kronecker]
+___________________________________________
+God made the natural number and all the rest is the work of man
+___________________________________________
+
+
+
+== Syntax (split slide)
+If your slide is too long, you can manually split it into multiple slides.
+
+syntax:
+
+...........................................
+ This line will be shown in current slide.
+
+ ifdef::backend-deckjs[<<<]
+
+ This line will be shown in next slide with the same title.
+...........................................
+
+effect:
+
+This line will be shown in current slide.
+
+ifdef::backend-deckjs[<<<]
+
+This line will be shown in next slide with the same title.
+
+
+== Syntax (insert image)
+
+syntax:
+
+...........................................
+image::http://www.gnu.org/graphics/gnu-head-sm.jpg[title="Texinfo"]
+...........................................
+
+effect:
+
+[incremental="true"]
+image::http://www.gnu.org/graphics/gnu-head-sm.jpg[title="Levitating GNU"]
+
+
+== Syntax (insert video)
+
+syntax:
+
+...........................................
+video::http://www.youtube.com/embed/GP3zvc2dG5Y[width="420", height="315"]
+...........................................
+
+effect:
+
+[incremental="true"]
+video::http://www.youtube.com/embed/GP3zvc2dG5Y[width="420", height="315"]
+
+
+== The End
+
+The source code for this slide can be found here:
+
+http://houqp.github.com/asciidoc-deckjs/tutorial-slide.asciidoc
+
+You can get start with following template:
+
+http://houqp.github.com/asciidoc-deckjs/example-template.asciidoc
+
+
+That's all. Hope you enjoy this backend. :-)
+
+
+
diff --git a/doc/draft_trex_stateless-docinfo.html b/doc/draft_trex_stateless-docinfo.html
new file mode 100755
index 00000000..a444f506
--- /dev/null
+++ b/doc/draft_trex_stateless-docinfo.html
@@ -0,0 +1,22 @@
+
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+
+<script src="my_chart.js"></script>
+
+<style>
+.axis path,
+.axis line {
+ fill: none;
+ stroke: #000;
+ shape-rendering: crispEdges;
+}
+
+.dot {
+ stroke: #000;
+}
+</style>
+
+
+
+
+
diff --git a/doc/draft_trex_stateless.asciidoc b/doc/draft_trex_stateless.asciidoc
new file mode 100755
index 00000000..d43ceeae
--- /dev/null
+++ b/doc/draft_trex_stateless.asciidoc
@@ -0,0 +1,17 @@
+TRex Stateless support
+======================
+:author: TRex team
+:email: trex.tgen@gmail.com
+:revnumber: 1.95
+:quotes.++:
+:numbered:
+:web_server_url: http://trex-tgn.cisco.com/trex
+:local_web_server_url: csi-wiki-01:8181/trex
+:github_stl_path: https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/stl
+:github_stl_examples_path: https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/automation/trex_control_plane/stl/examples
+:toclevels: 6
+
+moved to link:trex_stateless.html[trex_stateless.html]
+
+
+
diff --git a/doc/draft_trex_stateless_moved1.asciidoc b/doc/draft_trex_stateless_moved1.asciidoc
new file mode 100755
index 00000000..8cda35e5
--- /dev/null
+++ b/doc/draft_trex_stateless_moved1.asciidoc
@@ -0,0 +1,28 @@
+TRex Stateless support
+======================
+:author: TRex team
+:email: trex.tgen@gmail.com
+:revnumber: 2.0
+:quotes.++:
+:numbered:
+:web_server_url: http://trex-tgn.cisco.com/trex
+:local_web_server_url: csi-wiki-01:8181/trex
+:github_stl_path: https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/stl
+:github_stl_examples_path: https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/automation/trex_control_plane/stl/examples
+:toclevels: 6
+
+ifdef::backend-docbook[]
+:p_width: 450
+:p_width_1: 200
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+:p_width: 800
+:p_width_1: 400
+endif::backend-xhtml11[]
+
+include::trex_ga.asciidoc[]
+
+moved to link:draft_trex_stateless.html[here]
+
+
diff --git a/doc/images/128_nodrop.png b/doc/images/128_nodrop.png
new file mode 100755
index 00000000..e2a4c59a
--- /dev/null
+++ b/doc/images/128_nodrop.png
Binary files differ
diff --git a/doc/images/128_util.png b/doc/images/128_util.png
new file mode 100755
index 00000000..7dd7627e
--- /dev/null
+++ b/doc/images/128_util.png
Binary files differ
diff --git a/doc/images/1514_nodrop.png b/doc/images/1514_nodrop.png
new file mode 100755
index 00000000..34902725
--- /dev/null
+++ b/doc/images/1514_nodrop.png
Binary files differ
diff --git a/doc/images/1514_util.png b/doc/images/1514_util.png
new file mode 100755
index 00000000..7ad7d4da
--- /dev/null
+++ b/doc/images/1514_util.png
Binary files differ
diff --git a/doc/images/40425209_l.jpg b/doc/images/40425209_l.jpg
new file mode 100755
index 00000000..60bb3430
--- /dev/null
+++ b/doc/images/40425209_l.jpg
Binary files differ
diff --git a/doc/images/590_nodrop.png b/doc/images/590_nodrop.png
new file mode 100755
index 00000000..569bb9e7
--- /dev/null
+++ b/doc/images/590_nodrop.png
Binary files differ
diff --git a/doc/images/590_util.png b/doc/images/590_util.png
new file mode 100755
index 00000000..892caf0b
--- /dev/null
+++ b/doc/images/590_util.png
Binary files differ
diff --git a/doc/images/64_nodrop.png b/doc/images/64_nodrop.png
new file mode 100755
index 00000000..7dd7627e
--- /dev/null
+++ b/doc/images/64_nodrop.png
Binary files differ
diff --git a/doc/images/64_util.png b/doc/images/64_util.png
new file mode 100755
index 00000000..d3b6807e
--- /dev/null
+++ b/doc/images/64_util.png
Binary files differ
diff --git a/doc/images/Intel520.png b/doc/images/Intel520.png
new file mode 100755
index 00000000..ad67f3ec
--- /dev/null
+++ b/doc/images/Intel520.png
Binary files differ
diff --git a/doc/images/T-Rex_vm.png b/doc/images/T-Rex_vm.png
new file mode 100755
index 00000000..53340b9a
--- /dev/null
+++ b/doc/images/T-Rex_vm.png
Binary files differ
diff --git a/doc/images/TrexConfig.png b/doc/images/TrexConfig.png
new file mode 100755
index 00000000..1b956276
--- /dev/null
+++ b/doc/images/TrexConfig.png
Binary files differ
diff --git a/doc/images/TrexConfig_switch.png b/doc/images/TrexConfig_switch.png
new file mode 100755
index 00000000..245a849b
--- /dev/null
+++ b/doc/images/TrexConfig_switch.png
Binary files differ
diff --git a/doc/images/TrexViewer.png b/doc/images/TrexViewer.png
new file mode 100755
index 00000000..ad76dcc1
--- /dev/null
+++ b/doc/images/TrexViewer.png
Binary files differ
diff --git a/doc/images/bg4.jpg b/doc/images/bg4.jpg
new file mode 100644
index 00000000..e93f834b
--- /dev/null
+++ b/doc/images/bg4.jpg
Binary files differ
diff --git a/doc/images/checkbox.jpg b/doc/images/checkbox.jpg
new file mode 100755
index 00000000..38fa30e1
--- /dev/null
+++ b/doc/images/checkbox.jpg
Binary files differ
diff --git a/doc/images/cisco.png b/doc/images/cisco.png
new file mode 100755
index 00000000..1a2b826c
--- /dev/null
+++ b/doc/images/cisco.png
Binary files differ
diff --git a/doc/images/client_clustering_topology.png b/doc/images/client_clustering_topology.png
new file mode 100644
index 00000000..cb235c7a
--- /dev/null
+++ b/doc/images/client_clustering_topology.png
Binary files differ
diff --git a/doc/images/combo_button_choosing.jpg b/doc/images/combo_button_choosing.jpg
new file mode 100755
index 00000000..11483ed2
--- /dev/null
+++ b/doc/images/combo_button_choosing.jpg
Binary files differ
diff --git a/doc/images/combo_button_editing.jpg b/doc/images/combo_button_editing.jpg
new file mode 100755
index 00000000..ff8d3c49
--- /dev/null
+++ b/doc/images/combo_button_editing.jpg
Binary files differ
diff --git a/doc/images/console_link_down.png b/doc/images/console_link_down.png
new file mode 100755
index 00000000..16360cb0
--- /dev/null
+++ b/doc/images/console_link_down.png
Binary files differ
diff --git a/doc/images/core_mask_pin.png b/doc/images/core_mask_pin.png
new file mode 100644
index 00000000..63893484
--- /dev/null
+++ b/doc/images/core_mask_pin.png
Binary files differ
diff --git a/doc/images/core_mask_split.png b/doc/images/core_mask_split.png
new file mode 100644
index 00000000..7b0a456c
--- /dev/null
+++ b/doc/images/core_mask_split.png
Binary files differ
diff --git a/doc/images/different_numa.png b/doc/images/different_numa.png
new file mode 100755
index 00000000..a8be8a9e
--- /dev/null
+++ b/doc/images/different_numa.png
Binary files differ
diff --git a/doc/images/dns_wireshark.png b/doc/images/dns_wireshark.png
new file mode 100755
index 00000000..2d8010fc
--- /dev/null
+++ b/doc/images/dns_wireshark.png
Binary files differ
diff --git a/doc/images/icons/README b/doc/images/icons/README
new file mode 100755
index 00000000..f12b2a73
--- /dev/null
+++ b/doc/images/icons/README
@@ -0,0 +1,5 @@
+Replaced the plain DocBook XSL admonition icons with Jimmac's DocBook
+icons (http://jimmac.musichall.cz/ikony.php3). I dropped transparency
+from the Jimmac icons to get round MS IE and FOP PNG incompatibilies.
+
+Stuart Rackham
diff --git a/doc/images/icons/Thumbs.db b/doc/images/icons/Thumbs.db
new file mode 100755
index 00000000..a3487901
--- /dev/null
+++ b/doc/images/icons/Thumbs.db
Binary files differ
diff --git a/doc/images/icons/callouts/1.png b/doc/images/icons/callouts/1.png
new file mode 100755
index 00000000..054ea07a
--- /dev/null
+++ b/doc/images/icons/callouts/1.png
Binary files differ
diff --git a/doc/images/icons/callouts/10.png b/doc/images/icons/callouts/10.png
new file mode 100755
index 00000000..8833bd59
--- /dev/null
+++ b/doc/images/icons/callouts/10.png
Binary files differ
diff --git a/doc/images/icons/callouts/11.png b/doc/images/icons/callouts/11.png
new file mode 100755
index 00000000..d77914d8
--- /dev/null
+++ b/doc/images/icons/callouts/11.png
Binary files differ
diff --git a/doc/images/icons/callouts/12.png b/doc/images/icons/callouts/12.png
new file mode 100755
index 00000000..ac9f8af7
--- /dev/null
+++ b/doc/images/icons/callouts/12.png
Binary files differ
diff --git a/doc/images/icons/callouts/13.png b/doc/images/icons/callouts/13.png
new file mode 100755
index 00000000..e5e62a1f
--- /dev/null
+++ b/doc/images/icons/callouts/13.png
Binary files differ
diff --git a/doc/images/icons/callouts/14.png b/doc/images/icons/callouts/14.png
new file mode 100755
index 00000000..f55ef966
--- /dev/null
+++ b/doc/images/icons/callouts/14.png
Binary files differ
diff --git a/doc/images/icons/callouts/15.png b/doc/images/icons/callouts/15.png
new file mode 100755
index 00000000..fee9beda
--- /dev/null
+++ b/doc/images/icons/callouts/15.png
Binary files differ
diff --git a/doc/images/icons/callouts/2.png b/doc/images/icons/callouts/2.png
new file mode 100755
index 00000000..b05ad9c7
--- /dev/null
+++ b/doc/images/icons/callouts/2.png
Binary files differ
diff --git a/doc/images/icons/callouts/3.png b/doc/images/icons/callouts/3.png
new file mode 100755
index 00000000..9ce22b7d
--- /dev/null
+++ b/doc/images/icons/callouts/3.png
Binary files differ
diff --git a/doc/images/icons/callouts/4.png b/doc/images/icons/callouts/4.png
new file mode 100755
index 00000000..03d55928
--- /dev/null
+++ b/doc/images/icons/callouts/4.png
Binary files differ
diff --git a/doc/images/icons/callouts/5.png b/doc/images/icons/callouts/5.png
new file mode 100755
index 00000000..710b57cc
--- /dev/null
+++ b/doc/images/icons/callouts/5.png
Binary files differ
diff --git a/doc/images/icons/callouts/6.png b/doc/images/icons/callouts/6.png
new file mode 100755
index 00000000..65ce9b91
--- /dev/null
+++ b/doc/images/icons/callouts/6.png
Binary files differ
diff --git a/doc/images/icons/callouts/7.png b/doc/images/icons/callouts/7.png
new file mode 100755
index 00000000..07bc7f1c
--- /dev/null
+++ b/doc/images/icons/callouts/7.png
Binary files differ
diff --git a/doc/images/icons/callouts/8.png b/doc/images/icons/callouts/8.png
new file mode 100755
index 00000000..fc640cab
--- /dev/null
+++ b/doc/images/icons/callouts/8.png
Binary files differ
diff --git a/doc/images/icons/callouts/9.png b/doc/images/icons/callouts/9.png
new file mode 100755
index 00000000..5bbc0ad9
--- /dev/null
+++ b/doc/images/icons/callouts/9.png
Binary files differ
diff --git a/doc/images/icons/callouts/Thumbs.db b/doc/images/icons/callouts/Thumbs.db
new file mode 100755
index 00000000..2312a5bb
--- /dev/null
+++ b/doc/images/icons/callouts/Thumbs.db
Binary files differ
diff --git a/doc/images/icons/caution.png b/doc/images/icons/caution.png
new file mode 100755
index 00000000..9a8c515a
--- /dev/null
+++ b/doc/images/icons/caution.png
Binary files differ
diff --git a/doc/images/icons/example.png b/doc/images/icons/example.png
new file mode 100755
index 00000000..1199e864
--- /dev/null
+++ b/doc/images/icons/example.png
Binary files differ
diff --git a/doc/images/icons/home.png b/doc/images/icons/home.png
new file mode 100755
index 00000000..37a5231b
--- /dev/null
+++ b/doc/images/icons/home.png
Binary files differ
diff --git a/doc/images/icons/important.png b/doc/images/icons/important.png
new file mode 100755
index 00000000..be685cc4
--- /dev/null
+++ b/doc/images/icons/important.png
Binary files differ
diff --git a/doc/images/icons/next.png b/doc/images/icons/next.png
new file mode 100755
index 00000000..64e126bd
--- /dev/null
+++ b/doc/images/icons/next.png
Binary files differ
diff --git a/doc/images/icons/note.png b/doc/images/icons/note.png
new file mode 100755
index 00000000..7c1f3e2f
--- /dev/null
+++ b/doc/images/icons/note.png
Binary files differ
diff --git a/doc/images/icons/prev.png b/doc/images/icons/prev.png
new file mode 100755
index 00000000..3e8f12fe
--- /dev/null
+++ b/doc/images/icons/prev.png
Binary files differ
diff --git a/doc/images/icons/selected_tab_bg.png b/doc/images/icons/selected_tab_bg.png
new file mode 100644
index 00000000..16bb5d61
--- /dev/null
+++ b/doc/images/icons/selected_tab_bg.png
Binary files differ
diff --git a/doc/images/icons/tip.png b/doc/images/icons/tip.png
new file mode 100755
index 00000000..f087c73b
--- /dev/null
+++ b/doc/images/icons/tip.png
Binary files differ
diff --git a/doc/images/icons/toggle.png b/doc/images/icons/toggle.png
new file mode 100644
index 00000000..84380cd0
--- /dev/null
+++ b/doc/images/icons/toggle.png
Binary files differ
diff --git a/doc/images/icons/up.png b/doc/images/icons/up.png
new file mode 100755
index 00000000..2db1ce62
--- /dev/null
+++ b/doc/images/icons/up.png
Binary files differ
diff --git a/doc/images/icons/warning.png b/doc/images/icons/warning.png
new file mode 100755
index 00000000..d41edb9a
--- /dev/null
+++ b/doc/images/icons/warning.png
Binary files differ
diff --git a/doc/images/ip_allocation.png b/doc/images/ip_allocation.png
new file mode 100755
index 00000000..023706ef
--- /dev/null
+++ b/doc/images/ip_allocation.png
Binary files differ
diff --git a/doc/images/loopback_example.png b/doc/images/loopback_example.png
new file mode 100755
index 00000000..71cbb053
--- /dev/null
+++ b/doc/images/loopback_example.png
Binary files differ
diff --git a/doc/images/loopback_right.png b/doc/images/loopback_right.png
new file mode 100755
index 00000000..1891d25a
--- /dev/null
+++ b/doc/images/loopback_right.png
Binary files differ
diff --git a/doc/images/loopback_wrong.png b/doc/images/loopback_wrong.png
new file mode 100755
index 00000000..92602a86
--- /dev/null
+++ b/doc/images/loopback_wrong.png
Binary files differ
diff --git a/doc/images/passthrough_adding.png b/doc/images/passthrough_adding.png
new file mode 100755
index 00000000..4b2c3167
--- /dev/null
+++ b/doc/images/passthrough_adding.png
Binary files differ
diff --git a/doc/images/passthrough_marking.png b/doc/images/passthrough_marking.png
new file mode 100755
index 00000000..f3d4ac7b
--- /dev/null
+++ b/doc/images/passthrough_marking.png
Binary files differ
diff --git a/doc/images/rpc_server_big_picture.png b/doc/images/rpc_server_big_picture.png
new file mode 100755
index 00000000..01787f99
--- /dev/null
+++ b/doc/images/rpc_server_big_picture.png
Binary files differ
diff --git a/doc/images/rpc_server_big_picture_old.png b/doc/images/rpc_server_big_picture_old.png
new file mode 100644
index 00000000..dae6976d
--- /dev/null
+++ b/doc/images/rpc_server_big_picture_old.png
Binary files differ
diff --git a/doc/images/rpc_states.png b/doc/images/rpc_states.png
new file mode 100644
index 00000000..cdbf1c51
--- /dev/null
+++ b/doc/images/rpc_states.png
Binary files differ
diff --git a/doc/images/same_numa.png b/doc/images/same_numa.png
new file mode 100755
index 00000000..a9a0466e
--- /dev/null
+++ b/doc/images/same_numa.png
Binary files differ
diff --git a/doc/images/scapy_json_rpc_server.png b/doc/images/scapy_json_rpc_server.png
new file mode 100755
index 00000000..87050884
--- /dev/null
+++ b/doc/images/scapy_json_rpc_server.png
Binary files differ
diff --git a/doc/images/sfr_profile.png b/doc/images/sfr_profile.png
new file mode 100755
index 00000000..da9e5e62
--- /dev/null
+++ b/doc/images/sfr_profile.png
Binary files differ
diff --git a/doc/images/small.jpg b/doc/images/small.jpg
new file mode 100755
index 00000000..1557f126
--- /dev/null
+++ b/doc/images/small.jpg
Binary files differ
diff --git a/doc/images/smallnew.png b/doc/images/smallnew.png
new file mode 100755
index 00000000..411c2e17
--- /dev/null
+++ b/doc/images/smallnew.png
Binary files differ
diff --git a/doc/images/splitbar.png b/doc/images/splitbar.png
new file mode 100644
index 00000000..9c9c1988
--- /dev/null
+++ b/doc/images/splitbar.png
Binary files differ
diff --git a/doc/images/stateless_objects.png b/doc/images/stateless_objects.png
new file mode 100644
index 00000000..f16924da
--- /dev/null
+++ b/doc/images/stateless_objects.png
Binary files differ
diff --git a/doc/images/stateless_objects_02.png b/doc/images/stateless_objects_02.png
new file mode 100755
index 00000000..ea072d14
--- /dev/null
+++ b/doc/images/stateless_objects_02.png
Binary files differ
diff --git a/doc/images/stl_arp.png b/doc/images/stl_arp.png
new file mode 100644
index 00000000..4cba216a
--- /dev/null
+++ b/doc/images/stl_arp.png
Binary files differ
diff --git a/doc/images/stl_barrier.png b/doc/images/stl_barrier.png
new file mode 100644
index 00000000..a454e51b
--- /dev/null
+++ b/doc/images/stl_barrier.png
Binary files differ
diff --git a/doc/images/stl_barrier_02.png b/doc/images/stl_barrier_02.png
new file mode 100755
index 00000000..73bc8a65
--- /dev/null
+++ b/doc/images/stl_barrier_02.png
Binary files differ
diff --git a/doc/images/stl_barrier_03.png b/doc/images/stl_barrier_03.png
new file mode 100755
index 00000000..65cafca9
--- /dev/null
+++ b/doc/images/stl_barrier_03.png
Binary files differ
diff --git a/doc/images/stl_inter.png b/doc/images/stl_inter.png
new file mode 100644
index 00000000..0aeed52b
--- /dev/null
+++ b/doc/images/stl_inter.png
Binary files differ
diff --git a/doc/images/stl_interleaving_01.png b/doc/images/stl_interleaving_01.png
new file mode 100755
index 00000000..920c29eb
--- /dev/null
+++ b/doc/images/stl_interleaving_01.png
Binary files differ
diff --git a/doc/images/stl_loop_count_01.png b/doc/images/stl_loop_count_01.png
new file mode 100755
index 00000000..ee79c0e9
--- /dev/null
+++ b/doc/images/stl_loop_count_01.png
Binary files differ
diff --git a/doc/images/stl_loop_count_01b.png b/doc/images/stl_loop_count_01b.png
new file mode 100755
index 00000000..891f1a9b
--- /dev/null
+++ b/doc/images/stl_loop_count_01b.png
Binary files differ
diff --git a/doc/images/stl_multiple_clients_01.png b/doc/images/stl_multiple_clients_01.png
new file mode 100755
index 00000000..549daa2b
--- /dev/null
+++ b/doc/images/stl_multiple_clients_01.png
Binary files differ
diff --git a/doc/images/stl_multiple_clients_01b.png b/doc/images/stl_multiple_clients_01b.png
new file mode 100755
index 00000000..5e683448
--- /dev/null
+++ b/doc/images/stl_multiple_clients_01b.png
Binary files differ
diff --git a/doc/images/stl_multiple_streams_01.png b/doc/images/stl_multiple_streams_01.png
new file mode 100755
index 00000000..aa0615aa
--- /dev/null
+++ b/doc/images/stl_multiple_streams_01.png
Binary files differ
diff --git a/doc/images/stl_null_stream.png b/doc/images/stl_null_stream.png
new file mode 100644
index 00000000..8c415965
--- /dev/null
+++ b/doc/images/stl_null_stream.png
Binary files differ
diff --git a/doc/images/stl_null_stream_02.png b/doc/images/stl_null_stream_02.png
new file mode 100755
index 00000000..95fc7622
--- /dev/null
+++ b/doc/images/stl_null_stream_02.png
Binary files differ
diff --git a/doc/images/stl_streams_example.png b/doc/images/stl_streams_example.png
new file mode 100644
index 00000000..6c10e9d2
--- /dev/null
+++ b/doc/images/stl_streams_example.png
Binary files differ
diff --git a/doc/images/stl_streams_example.vsd b/doc/images/stl_streams_example.vsd
new file mode 100644
index 00000000..38ff194b
--- /dev/null
+++ b/doc/images/stl_streams_example.vsd
Binary files differ
diff --git a/doc/images/stl_streams_example_02.png b/doc/images/stl_streams_example_02.png
new file mode 100755
index 00000000..7b7f1f33
--- /dev/null
+++ b/doc/images/stl_streams_example_02.png
Binary files differ
diff --git a/doc/images/stl_tut_1.png b/doc/images/stl_tut_1.png
new file mode 100644
index 00000000..24aa26fc
--- /dev/null
+++ b/doc/images/stl_tut_1.png
Binary files differ
diff --git a/doc/images/stl_tut_12.png b/doc/images/stl_tut_12.png
new file mode 100644
index 00000000..0db7f117
--- /dev/null
+++ b/doc/images/stl_tut_12.png
Binary files differ
diff --git a/doc/images/stl_tut_4.png b/doc/images/stl_tut_4.png
new file mode 100644
index 00000000..dbe95fba
--- /dev/null
+++ b/doc/images/stl_tut_4.png
Binary files differ
diff --git a/doc/images/stl_tut_pcap_file1.png b/doc/images/stl_tut_pcap_file1.png
new file mode 100644
index 00000000..1e4be64e
--- /dev/null
+++ b/doc/images/stl_tut_pcap_file1.png
Binary files differ
diff --git a/doc/images/trex-asr-setup.png b/doc/images/trex-asr-setup.png
new file mode 100644
index 00000000..3cc89d76
--- /dev/null
+++ b/doc/images/trex-asr-setup.png
Binary files differ
diff --git a/doc/images/trex-not-supported-setup.png b/doc/images/trex-not-supported-setup.png
new file mode 100644
index 00000000..5b0ac3ce
--- /dev/null
+++ b/doc/images/trex-not-supported-setup.png
Binary files differ
diff --git a/doc/images/trex2.png b/doc/images/trex2.png
new file mode 100755
index 00000000..2bed6ab3
--- /dev/null
+++ b/doc/images/trex2.png
Binary files differ
diff --git a/doc/images/trex_2.0_stateless.png b/doc/images/trex_2.0_stateless.png
new file mode 100644
index 00000000..01787f99
--- /dev/null
+++ b/doc/images/trex_2.0_stateless.png
Binary files differ
diff --git a/doc/images/trex_2_stateless.png b/doc/images/trex_2_stateless.png
new file mode 100644
index 00000000..5208fe49
--- /dev/null
+++ b/doc/images/trex_2_stateless.png
Binary files differ
diff --git a/doc/images/trex_algo.png b/doc/images/trex_algo.png
new file mode 100755
index 00000000..6da98473
--- /dev/null
+++ b/doc/images/trex_algo.png
Binary files differ
diff --git a/doc/images/trex_architecture_01.png b/doc/images/trex_architecture_01.png
new file mode 100755
index 00000000..a2a6fec2
--- /dev/null
+++ b/doc/images/trex_architecture_01.png
Binary files differ
diff --git a/doc/images/trex_auto_script.jpg b/doc/images/trex_auto_script.jpg
new file mode 100755
index 00000000..f4cdb109
--- /dev/null
+++ b/doc/images/trex_auto_script.jpg
Binary files differ
diff --git a/doc/images/trex_control_plane_modules.png b/doc/images/trex_control_plane_modules.png
new file mode 100755
index 00000000..c4978e38
--- /dev/null
+++ b/doc/images/trex_control_plane_modules.png
Binary files differ
diff --git a/doc/images/trex_desing.png b/doc/images/trex_desing.png
new file mode 100755
index 00000000..64b3ed1c
--- /dev/null
+++ b/doc/images/trex_desing.png
Binary files differ
diff --git a/doc/images/trex_generator_1.PNG b/doc/images/trex_generator_1.PNG
new file mode 100755
index 00000000..8b0d57a8
--- /dev/null
+++ b/doc/images/trex_generator_1.PNG
Binary files differ
diff --git a/doc/images/trex_logo.png b/doc/images/trex_logo.png
new file mode 100755
index 00000000..3bf29278
--- /dev/null
+++ b/doc/images/trex_logo.png
Binary files differ
diff --git a/doc/images/trex_logo_64_64.png b/doc/images/trex_logo_64_64.png
new file mode 100755
index 00000000..286228b6
--- /dev/null
+++ b/doc/images/trex_logo_64_64.png
Binary files differ
diff --git a/doc/images/trex_logo_green_small.png b/doc/images/trex_logo_green_small.png
new file mode 100755
index 00000000..0cc7221a
--- /dev/null
+++ b/doc/images/trex_logo_green_small.png
Binary files differ
diff --git a/doc/images/trex_logo_toc.png b/doc/images/trex_logo_toc.png
new file mode 100644
index 00000000..eb9fa1ec
--- /dev/null
+++ b/doc/images/trex_logo_toc.png
Binary files differ
diff --git a/doc/images/trex_model.png b/doc/images/trex_model.png
new file mode 100755
index 00000000..1bdcfca4
--- /dev/null
+++ b/doc/images/trex_model.png
Binary files differ
diff --git a/doc/images/trex_motinor_config.png b/doc/images/trex_motinor_config.png
new file mode 100755
index 00000000..70f705ce
--- /dev/null
+++ b/doc/images/trex_motinor_config.png
Binary files differ
diff --git a/doc/images/trex_motinor_view.png b/doc/images/trex_motinor_view.png
new file mode 100755
index 00000000..855dc027
--- /dev/null
+++ b/doc/images/trex_motinor_view.png
Binary files differ
diff --git a/doc/images/trex_sfr_profile.png b/doc/images/trex_sfr_profile.png
new file mode 100755
index 00000000..f90caa42
--- /dev/null
+++ b/doc/images/trex_sfr_profile.png
Binary files differ
diff --git a/doc/images/trex_stateless_multi_user.png b/doc/images/trex_stateless_multi_user.png
new file mode 100644
index 00000000..132b4250
--- /dev/null
+++ b/doc/images/trex_stateless_multi_user.png
Binary files differ
diff --git a/doc/images/trex_stateless_multi_user_02.png b/doc/images/trex_stateless_multi_user_02.png
new file mode 100755
index 00000000..87d64c83
--- /dev/null
+++ b/doc/images/trex_stateless_multi_user_02.png
Binary files differ
diff --git a/doc/images/trex_stl_gui.png b/doc/images/trex_stl_gui.png
new file mode 100644
index 00000000..59764b96
--- /dev/null
+++ b/doc/images/trex_stl_gui.png
Binary files differ
diff --git a/doc/images/trex_vm_bios_err.png b/doc/images/trex_vm_bios_err.png
new file mode 100755
index 00000000..3ac2da5d
--- /dev/null
+++ b/doc/images/trex_vm_bios_err.png
Binary files differ
diff --git a/doc/images/trex_vm_login.png b/doc/images/trex_vm_login.png
new file mode 100755
index 00000000..388ee4ba
--- /dev/null
+++ b/doc/images/trex_vm_login.png
Binary files differ
diff --git a/doc/images/trex_vm_run.png b/doc/images/trex_vm_run.png
new file mode 100755
index 00000000..86d1cf19
--- /dev/null
+++ b/doc/images/trex_vm_run.png
Binary files differ
diff --git a/doc/images/ucs200_2.png b/doc/images/ucs200_2.png
new file mode 100755
index 00000000..52cb10f4
--- /dev/null
+++ b/doc/images/ucs200_2.png
Binary files differ
diff --git a/doc/images/vSwitch_loopback.png b/doc/images/vSwitch_loopback.png
new file mode 100755
index 00000000..6becc4d7
--- /dev/null
+++ b/doc/images/vSwitch_loopback.png
Binary files differ
diff --git a/doc/images/vSwitch_main.png b/doc/images/vSwitch_main.png
new file mode 100755
index 00000000..37e0b08e
--- /dev/null
+++ b/doc/images/vSwitch_main.png
Binary files differ
diff --git a/doc/images/vSwitch_networks.png b/doc/images/vSwitch_networks.png
new file mode 100755
index 00000000..eca79142
--- /dev/null
+++ b/doc/images/vSwitch_networks.png
Binary files differ
diff --git a/doc/images/vm_import.png b/doc/images/vm_import.png
new file mode 100755
index 00000000..e3b28647
--- /dev/null
+++ b/doc/images/vm_import.png
Binary files differ
diff --git a/doc/images/vm_selection_screen.png b/doc/images/vm_selection_screen.png
new file mode 100755
index 00000000..a2c8e19b
--- /dev/null
+++ b/doc/images/vm_selection_screen.png
Binary files differ
diff --git a/doc/my_chart.js b/doc/my_chart.js
new file mode 100755
index 00000000..41851e0f
--- /dev/null
+++ b/doc/my_chart.js
@@ -0,0 +1,84 @@
+function chart(id,data,data_names,xlabel,ylabel){
+
+var margin = {_myt: 20, _right: 20, _bottom: 30, _left: 40};
+
+var width = 960 - margin._left - margin._right;
+var height = 500 - margin._myt - margin._bottom;
+
+var x = d3.scale.linear()
+ .range([0, width]);
+
+var y = d3.scale.linear()
+ .range([height, 0]);
+
+var color = d3.scale.category10();
+
+var xAxis = d3.svg.axis()
+ .scale(x)
+ .orient("bottom");
+
+var yAxis = d3.svg.axis()
+ .scale(y)
+ .orient("left");
+
+var svg = d3.select(id).append("svg")
+ .attr("width", width + margin._left + margin._right)
+ .attr("height", height + margin._myt + margin._bottom)
+ .append("g")
+ .attr("transform", "translate(" + margin._left + "," + margin._myt + ")");
+
+x.domain(d3.extent(data, function(d) { return d[0] })).nice();
+y.domain(d3.extent(data, function(d) { return d[1] })).nice();
+
+svg.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0," + height + ")")
+ .call(xAxis)
+ .append("text")
+ .attr("class", "label")
+ .attr("x", width)
+ .attr("y", -6)
+ .style("text-anchor", "end")
+ .text(xlabel);
+
+svg.append("g")
+ .attr("class", "y axis")
+ .call(yAxis)
+ .append("text")
+ .attr("class", "label")
+ .attr("transform", "rotate(-90)")
+ .attr("y", 6)
+ .attr("dy", ".71em")
+ .style("text-anchor", "end")
+ .text(ylabel)
+
+svg.selectAll(".dot")
+ .data(data)
+ .enter().append("circle")
+ .attr("class", "dot")
+ .attr("r", 3.5)
+ .attr("cx", function(d) { return x(d[0]); })
+ .attr("cy", function(d) { return y(d[1]); })
+ .style("fill", function(d) { return color(d[2]); });
+
+var legend = svg.selectAll(".legend")
+ .data(color.domain())
+ .enter().append("g")
+ .attr("class", "legend")
+ .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
+
+legend.append("rect")
+ .attr("x", width - 18)
+ .attr("width", 18)
+ .attr("height", 18)
+ .style("fill", color);
+
+legend.append("text")
+ .attr("x", width - 24)
+ .attr("y", 9)
+ .attr("dy", ".35em")
+ .style("text-anchor", "end")
+ .text(function(d) { return data_names[d]; });
+
+}
+
diff --git a/doc/packet_builder_yaml.asciidoc b/doc/packet_builder_yaml.asciidoc
new file mode 100755
index 00000000..ed80358e
--- /dev/null
+++ b/doc/packet_builder_yaml.asciidoc
@@ -0,0 +1,674 @@
+Packet Builder Language
+=======================
+:author: hhaim
+:email: <hhaim@cisco.com>
+:revnumber: 0.04
+:quotes.++:
+:numbered:
+
+
+== change log
+
+include::trex_ga.asciidoc[]
+
+
+[options="header",cols="^1,^h,a"]
+|=================
+| Version | name | meaning
+| 0.01 | hhaim |
+- first version
+| 0.02 | hhaim
+|
+- change the bool fields to properties
+- add external/internal property
+- add const property ( instead cant_change)
+- change TLV property - now learn the prev header
+- add choice of next protocol that is not base on a field ( TCP->IP->TCP)
+| 0.03 | ybrustin
+|
+- add MAC address regexp
+- add gui_representation class with data_type, form_type, combobox_values, data_type_regexp items to describe GUI view of field
+- rename choice attribute to value_based_next_header
+- fixed some typos
+| 0.04 | ybrustin
+|
+- change value_based_next_header, combobox_values (to be consistent with value_based_next_header) to dictionary
+- added value_based_next_class for options
+- move 'help' attribute to gui_representation
+- add link to headers.yaml (references at bottom of the page)
+
+|=================
+
+
+== A file format for GUI packet builder
+
+=== Introduction
+
+We would like a file that will be read by GUI and will give us the ability to build packets using GUI
+
+The format should be *YAML*
+
+
+=== High Level Requirement
+
+* Define a YAML object format for dynamic building of packets and a program that change various fields
+* Ability to *parse* back the same buffer that was created using this tool (reversibility)
+** Ability to load packet from a pcap file and parse it
+* Ability to save the packet to a pcap file
+* Ability to save the packet and program in JSON format (same JSON-RPC format)
+* Set a value for any field of any protocol
+* Vary packet fields across packets at run time e.g. changing IP/MAC addresses
+* Stack protocols in any arbitrary order define in YAML format
+
+=== Header that should be supported (first phase)
+
+==== L2
+
+* Ethernet
+* 802.3
+* LLC SNAP
+* VLAN (with QinQ) stack
+* MPLS stack
+
+==== L3
+
+* ARP
+* IPv4
+* IPv6 (4x header)
+* IP-in-IP a.k.a IP Tunnelling (6over4, 4over6, 4over4, 6over6)
+
+==== L4
+
+* TCP
+* UDP
+* ICMPv4
+* ICMPv6
+* IGMP
+
+==== L7 anchor:Payload[]
+
+* Any text based protocol (HTTP, SIP, RTSP, NNTP etc.)
+** random string
+** repeat string
+
+* Pattern Binary
+** repeat of value (e.g 0x55)
+** random
+** seq (1,2,3,3,4)
+** User Hex Dump editor
+
+
+=== YAML Format
+
+==== Header section
+
+.Default Types anchor:Types[]
+[options="header",cols="1,2,3"]
+|=================
+| Field Name | meaning | size in bits
+| bit | describe the header object e.g tcp | 1
+| uint8 | describe the header object e.g tcp | 8
+| uint16 | the name in the GUI | 16
+| uint32 | sub fields of this header | 32
+| uint64 | sub fields of this header | 64
+| other class type | name of other class. for example, "c-mac-addr"; take fields from there, optionally overload them later | The size taken from that class
+| Payload | xref:Payload[Payload] | total packet size - all header until now
+| vlen_t | in case of varible size header this include the size to the end of varible size header see example xref:IpvOption[Ipv4Option] |total size of the object
+|=================
+
+
+.Default Data_Type anchor:Data_Type[]
+[options="header",cols="1,2"]
+|=================
+| Field Name | meaning
+| none | use Hex Editor as Types
+| ipv4_t | 4 decimals 0-255 each
+| mac_addr_t | ([0-9a-fA-F]\{2\}:)\{5\}[0-9a-fA-F]\{2\}
+| ipv4_mask_t | should match uint32 type
+| ipv6_t | should have 16 bytes field size 8x16
+| ipv6_mask_t | should have 16 bytes field size 8x16
+| another header class | sub fields of this header
+| char_t | array of bytes , look into the array_size of cost string
+| var_char_t | array based on a field value look into
+| regexp_t | define a Java function that converts a reg exp string to a buffer see here xref:GenRegExp[RegExp]
+|=================
+
+.Default Form_Type anchor:Form_Type[]
+[options="header",cols="1,3"]
+|=================
+| Field Name | meaning
+| none | simple editing field
+| combo_with_edit | combo box with predefined choices, can edit the field value manually
+| combo_without_edit | combo box with predefined choices, can [underline]#not# edit the field value manually
+| checkbox | toggle bits values, if item is array of bits, display several checkboxes per number of bits
+|=================
+
+
+.Default Gui_Representation anchor:Gui_Representation[]
+[options="header",cols="1,^1,5,^1,10"]
+|=================
+| Field Name | value type | meaning | Link | Additional info
+| help | string | the name in the GUI | |
+| data_type | string | how to represent data | xref:Data_Type[Data_Type] | data_type could get data_type_regexp e.g data_type = "ipv4"; data_type = "regexp" data_type_regexp = "string that define regexp and Java function"
+| form_type | string | which editing form to use | xref:Form_Type[Form_Type] | for example for ip address use combobox with option to edit value manually or choose: key "localhost" value "127.0.0.1" etc.
+| combobox_values | dictionary | pairs of 'key - value' for combo_with/without_edit | |
+| data_type_regexp | string | in case it is reg_exp the name of the function | xref:GenRegExp[GenRegExp] |
+|=================
+
+
+.Default Properties anchor:Properties[]
+[options="header",cols="1,7"]
+|=================
+| Field Name | meaning
+| ipv4_checksum | auto calculates checksum on this header Ipv4 type
+| tcp_checksum | calculate TCP checksum
+| udp_checksum | calculate UDP checksum
+| ipv4_total_length | calculate ipv4 total length this pkt_size = header + reset of packet
+| tlv | TLV length of the header (inlcudes the prev field length) example ip-option, tcp-option
+| le | little endian. deault is big
+| const | const field for example the 4 version of ipv4 header - this GUI won't give option to change this field
+| external | marks the header as an external header for the GUI. for example IPv4 is external header and mac-addr is internal header ( compose external header)
+|=================
+
+
+.Field_Type anchor:Field_Type[]
+[options="header",cols="1,^1,30,^1,^1,30"]
+|=================
+| Field Name | value type | meaning | Default Value | Link | Example
+| class | string | describe the class type | in case class is defined no need to have name and vise versa | | class : tcp
+| name | string | describe the instance name | in case class is defined no need to have name and vise versa | | name : tcp
+| array_size | integer | how many objects of this type, default value is 1 | 1 | | array_size : 6 in case of mac-addr
+| type | string | type, see Types define the size | "uint8_t" | xref:Types[Types] | type : "uint32_t" type : "mac_addr"
+| gui_representation | dictionary | description of how to view/edit data in GUI | | xref:Gui_Representation[Gui_Representation] | xref:Gui_Representation_Example[Gui_Representation_Example]
+| default | array/value | default value in the packets , you can override value for subfields in parent see example
+| [0 ]x header size | | xref:Overide_Subfields_Example[Overide_Subfields_Example]
+| properies | array of string like masks
+| properies of this fields | [] | xref:Properties[Properties] | ["le","external"] , ["tlv","le","const"]
+| value_based_next_header | dictionary | define the next protocol based on a field value | none | xref:Value_Based_Next_Header[Value_Based_Next_Header] |
+| value_based_next_class | dictionary | define the next class based on a field value (useful for options) | none | xref:Value_Based_Next_Class[Value_Based_Next_Class] |
+| next_headers | string or type | a name of class that define the next or just an array | "none" | xref:Next_headers[Next_headers] |
+| fields | array | array of Field_Type | [] | | fields : [ ]
+| offset | integer/string | offset into the packet in bits, in case of auto add base of prev fields | "auto" | |
+| option | string | a java code that define a way to calculate varible size | "none" | | |
+|=================
+
+
+.Field_Type anchor:ConstHeadesClass[]
+[options="header",cols="^1,^10"]
+|=================
+| Field Name | value type
+| "root" | the root pointer to the start of blocks L2/802.3 etc
+| "end" | end TLV headers
+| "payload" | the rest of the packets as buffer/string etc
+|=================
+
+
+.Next_headers anchor:Next_headers[]
+Example of Next_headers
+[source,python]
+----
+
+ - class : "next-example-t-1"
+ gui_representation:
+ help : "next-example-t-1"
+ next_headers : ["ipv4", "ipv6, "tcp"]
+
+# option 1 define in the header itself
+ - class : "tcp"
+ gui_representation:
+ help : "TCP header"
+ properies : ["external"]
+ next_headers : ["ipv4", "ipv6, "tcp"]
+ fields :
+ - name : "ver"
+
+# option 2 define throw a class
+ - class : "tcp"
+ gui_representation:
+ help : "TCP header"
+ properies : ["external"]
+ next_headers : "next-example-t-1" #
+ fields :
+ - name : "ver"
+----
+
+
+.Value_Based_Next_Header anchor:Value_Based_Next_Header[]
+Example of value_based_next_header
+[source,python]
+----
+ value_based_next_header:
+ 0x0800: 'ipv4'# name of an external or internal class , the GUI should distinct betwean internal and external
+ 0x0806: 'arp'
+ 0x86DD: 'ipv6'
+ 0x8100: 'vlan'
+ 0x8847: 'mpls unicast'
+ default: 'payload' # if no match for any of above
+
+----
+
+
+.Generic RegExp Edit Field anchor:GenRegExp[]
+
+This will define a regexp that match for user input and how to converts it to buffer of bytes
+
+[source,python]
+----
+
+class MyClass : public RegExpBase {
+ public:
+
+
+ string get_reg_exp_string( ) {
+ return ((\d){1-3})[.]((\d){1-3})[.]((\d){1-3})[.]((\d){1-3}))
+ }
+
+ # in case of match
+ buffer get_buffer(){
+ g= [get_group()[1].to_int()*256,get_group()[1].to_int()]
+ # return list
+ return (g)
+ }
+
+}
+
+----
+
+
+
+==== Relations between object headers
+
+There would be a root object to point to possible starting headers
+
+
+[source,python]
+----
+
+- class : "root"
+ gui_representation:
+ help : "Root"
+ next_headers : [ "ethernet", "llc", "_802-3"]
+----
+
+So in a way you could define a tree like this
+
+[source,python]
+----
+
+root -> L2 ( Ethernet , 802.3 , LLC SNAP )
+ |( by field )
+ |
+ ------------------------------------- ( VLAN (with QinQ), MPLS , ipv4, ipv6, ARP , ICMP )
+ | | | |
+ | ipv4/ipv6 - -
+ | |
+ | |
+ [Possibility - Ethernet/802.3/LLC SNAP) | UDP/TCP/Pyload
+ Object | |
+ for each option there tree of all the option --- -
+----
+
+
+==== Rules
+
+* The size of the header and offset is automatically defined in default by the order of the fields ( inc by type size multiply by array_size)
+* It can be overrided by offset field ( put offset in the object ) and then an more advanced field can be shown earlier in the GUI
+* The packet size is defined before the headers. Header Should not be allowed to be added if the size + header size is bigger than packet size
+* "Payload" is predefined Fields that take the reset of the packet and user can edit it ( see xref:Payload[Payload] )
+* There would be a spare field in the Stream object so GUI could add more metadata for reconstructing the builder types
+ for example in this example Ethrenet/IP/TCP/IP/TCP you can't extrac from buffer alone that Payload is IP/TCP only the builder known that in build time.
+* Ip total length need to keep the total_pkt_size - this ip header . this should work for internal header too.
+* When GUI add header ("external") the total size of this header should be calculated ( varible size should be given a default - ipv4)
+
+
+=== Examples
+
+
+==== TLV (Ip option) anchor:IpvOption[], value_based_next_class anchor:Value_Based_Next_Class[]
+
+
+IP-option see link:http://tools.ietf.org/html/rfc791[ip_option]
+
+0 : END
+
+1 : Length 1
+
+other : Byte : Length ( +first) |option
+
+
+
+[source,python]
+----
+
+ - class : "ip_option_131"
+ gui_representation:
+ help : "ip_option"
+ fields :
+ - name : "length" # tree with leaf of bits
+ gui_representation:
+ help : "length"
+ type : uint8
+ properties : ["tlv"] # the length include the prev field size (8 byte)
+
+ - name : "pointer" # tree with leaf of bits
+ type : uint8
+
+ - name : "buffer" # tree with leaf of bits
+ type : "tlv_reset"
+
+ - class : "default_ip4_option_tlv"
+ gui_representation:
+ help : "ip_option"
+ fields :
+ - name : "length" # tree with leaf of bits
+ gui_representation:
+ help : "length"
+ type : uint8
+ properties : "tlv" # the length include the prev field size (8 byte)
+
+ - name : "buffer" # tree with leaf of bits
+ type : "vlen_t"
+
+
+ - class : "ip_option"
+ gui_representation:
+ help : "ip_option"
+ type : uint8
+ default : [0x01]
+ value_based_next_class :
+ 0x00 : "end" # reserve name for ending the loop
+ 0x01 : "ip_option" # back to this header
+ 0x131 : "ip_option_131"
+ 0x0812: "gre"
+ default : "default_ip4_option_tlv"
+
+
+----
+
+* case of varible length field ip_option example
+
+
+
+==== Example TCP/IP
+
+
+[source,python]
+----
+
+ - class : "c-mac-addr"
+ type : "uint8"
+ array_size : 6
+ default : [0x00, 0x00, 0x01, 0x00, 0x00, 0x00]
+ gui_representation:
+ data_type : "mac-addr_t" # format ([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}
+ help : "Mac addrees"
+
+
+ - class : "ethernet"
+ gui_representation:
+ help : "Ethernet-L2"
+ properties: ['external']
+ fields :
+ - name : "Dst"
+ gui_representation:
+ help : "destination mac"
+ type : "c-mac-addr"
+
+ - name : "Src"
+ gui_representation:
+ help : "source mac"
+ type : "c-mac-addr"
+
+ - name: "Ethertype"
+ gui_representation:
+ help: "Ethertype"
+ type: "uint16"
+ default: [0x0800]
+ value_based_next_header :
+ 0x0800 : "ipv4"
+ 0x86DD : "ipv6"
+ 0x8100 : "vlan"
+ 0x8847 : "mpls" #unicast
+ default : "payload"
+
+
+ - class : "ipv4"
+ gui_representation:
+ help : "Ipv4"
+ fields :
+ - name : "ver"
+ gui_representation:
+ help : "Version"
+ type : "bit"
+ array_size : 4
+ default : [0, 1, 0, 0]
+ properties : ["const"]
+
+ - name : "ihl"
+ type : "bit"
+ array_size : 4
+ default : [0, 1, 1, 1]
+ properties : ["ipv4_ihl"]
+ gui_representation:
+ help : "IHL"
+ form_type: "checkbox"
+
+ ..
+
+ - name : "hdr_chsum"
+ gui_representation:
+ help : "Header Checksum"
+ default : [0x00,0x00]
+ properties : ["ipv4_check_sum", "const"]
+
+ - name : "total_len"
+ gui_representation:
+ help : "Total Length"
+ default : [0x00,0x00]
+ properties : ["ipv4_total_len", "const"] # auto calculate total_size-offset_header
+
+ - name : "protocol"
+ type : uint8
+ default : 0x06
+ value_based_next_header : &ipv4_next_header
+ 0x06 : "tcp"
+ 0x11 : "udp"
+ 0x29 : "ipv6"
+ 0x2F : "gre"
+ default : "payload"
+ gui_representation:
+ help : "IPv4 next Protocol"
+ form_type: "combo_without_edit"
+ combobox_values:
+ <<: *ipv4_next_header # take same choices as value_based_next_header
+
+ - name : "src_addr"
+ type : uint32
+ default : [16, 0, 0, 0]
+ gui_representation:
+ help : "Source Address"
+ data_type : "ipv4" # reserve
+
+ - name : "dst_addr"
+ default : [48, 0, 0, 0]
+ type : uint32
+ gui_representation:
+ help : "Destination Address"
+ data_type : "ipv4" # reserve
+ form_type : "combo_with_edit"
+ combobox_values:
+ [127, 0, 0, 1]: 'localhost'
+ [255, 255, 255, 255]: 'broadcast'
+
+
+ - class : "tcp"
+ gui_representation:
+ help : "TCP"
+ properties : ["external"]
+ fields :
+ - name : "src_port"
+ gui_representation:
+ help : "Source Port"
+ default : [0x30,0x00]
+ type : uint16
+
+ - name : "dest_port"
+ gui_representation:
+ help : "Source Port"
+ default : [0x30,0x00]
+ type : uint16
+
+ - name : "seq"
+ gui_representation:
+ help : "Seq Number"
+ type : uint32
+ default : [0x30,0x00,00,00]
+
+ - name : "ack"
+ gui_representation:
+ help : "Ack Number"
+ type : uint32
+ default : [0x30,0x00,00,00]
+
+ ...
+
+ - name : "flags" # tree with leaf of bits
+ gui_representation:
+ help : "Ack Number"
+ type : uint8
+ default : [0x30]
+ fields :
+ - name : "urg"
+ help : "URG"
+ type : bit
+ default : [0x0]
+
+ - name : "ack"
+ help : "ACK"
+ type : bit
+ default : [0x1]
+ ..
+
+ - name : "checksum"
+ gui_representation:
+ help : "TCP Checksum"
+ type : uint16
+ default : [0x00,0x00]
+ properties : ["tcp_checksum"] # auto calculate total_size-offset_header
+
+
+- class : "root" # reserve
+ gui_representation:
+ help : "Root"
+ next_headers : [ "ethrenet" ,"llc","_802-3"]
+---------------------------
+
+
+==== Overide subfields example anchor:Overide_Subfields_Example[]
+
+In this example parent class default value overrides default values of sub-fields ( 2 different mac-addr)
+
+[source,python]
+----
+
+ - class : "c-mac-addr"
+ type : "uint8"
+ array_size : 6
+ gui_representation:
+ help : "Mac addrees"
+ data_type : "mac-addr_t" # format ([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}
+ default : [0x00,0x00,0x01,0x00,0x00,0x00]
+
+
+ - class : "ethernet"
+ gui_representation:
+ help : "Ethernet-L2"
+ properties : ["external"]
+ default : [0x00,0x01,0x01,0x00,0x00,0x00, 0x00,0x02,0x02,0x00,0x00,0x00 ,0x08,00] # change the default of sub-fields . it is const size
+ fields :
+ - name : "Dst"
+ gui_representation:
+ help : "destination mac"
+ type : "c-mac-addr"
+
+ - name : "Src"
+ gui_representation:
+ help : "source mac"
+ type : "c-mac-addr"
+
+ - name : "ip_protocol"
+ type : "uint16_t"
+ default : [0x08,0x00]
+ value_based_next_header :
+ 0x0800 : "ipv4"
+ 0x86DD : "ipv6"
+ 0x8100 : "vlan"
+ 0x8847 : "mpls unicast"
+ default : "payload"
+----
+
+==== Gui Representation example anchor:Gui_Representation_Example[]
+[underline]#In YAML:#
+[source,python]
+----
+ - name: 'Flags'
+ type: 'bit'
+ array_size: 3
+ gui_representation:
+ help: 'IPv4 Flags'
+ form_type: 'checkbox' # can check each bit
+
+
+ - name: 'dst_addr'
+ default: [48, 0, 0, 0]
+ type: uint32
+ gui_representation:
+ help: 'IPv4 Destination Address'
+ data_type: 'ipv4_t' # special representation case, show as 4 decimal numbers
+ form_type: 'combo_with_edit' # can choose from pre-defined values or edit manually
+ combobox_values:
+ [127, 0, 0, 1]: 'localhost'
+ [255, 255, 255, 255]: 'broadcast'
+
+
+ - name: 'protocol'
+ type: uint8
+ default: 0x06
+ value_based_next_header: &ipv4_next_header
+ 0x06: 'tcp'
+ 0x11: 'udp'
+ default : "payload"
+ gui_representation:
+ help: 'IPv4 Protocol Field'
+ form_type: 'combo_without_edit' # choose from supported protocols, no manual edit
+ combobox_values:
+ <<: *ipv4_next_header # take same choices as value_based_next_header
+----
+
+[underline]#In GUI:#
+
+checkbox for bits:
+
+image:images/checkbox.jpg[]
+
+editing in combo-box:
+
+image:images/combo_button_editing.jpg[]
+
+choosing from predefined values:
+
+image:images/combo_button_choosing.jpg[]
+
+==== Union base
+
+TBD
+
+
+
+=== Resource
+* link:yaml/headers.yaml[headers.yaml]
+* link:https://wireedit.com/[WireEdit]
+* link:http://ostinato.org/[ostinato]
+* link:http://www.slideshare.net/nlekh/ixiaexplorer[IxExplorer]
+
+
diff --git a/doc/release_notes.asciidoc b/doc/release_notes.asciidoc
new file mode 100755
index 00000000..b37e467e
--- /dev/null
+++ b/doc/release_notes.asciidoc
@@ -0,0 +1,562 @@
+:author: hhaim
+:email: <hhaim@cisco.com>
+
+
+ifndef::backend-docbook[]
+++++++++++++++
+<div id="header-pic" style="padding:50px;margin-top:0px;position:absolute;left:0px;width:100%;">
+ <img src="images/trex_logo.png" alt="Smiley face" height="80" width="270"/>
+</div>
+<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
+++++++++++++++
+
+include::trex_ga.asciidoc[]
+
+
+== TRex release notes ==
+endif::backend-docbook[]
+
+ifdef::backend-docbook[]
+
+== TRex release notes ==
+:numbered:
+
+endif::backend-docbook[]
+
+== Release 2.10 ==
+
+* Added support for IP based configuration files (As opposed to MAC based used until now), with the ability of TRex to send
+ARP requests for default gateway, and gratitues ARP for its own addresses.
+See link:trex_manual.html#_configuration_yaml_parameter_of_cfg_option[here] and link:trex_config_guide.html[here] for details.
+* Added commands/API to Stateless client/console:
+** Getting extended counters of port for improved debug purposes. See example: link:trex_stateless.html#_stats[stats]
+** Changing of port attributes and getting async feedback on the changed status. See example: link:trex_stateless.html#_portattr[portattr]
+* For developers - added/updated RPC commands (which can be used for GUI etc.):
+** Getting system info added new options, for example description of interface: link:trex_rpc_server_spec.html#_get_system_info[get_system_info]
+** Setting port attributes added new options: link:trex_rpc_server_spec.html#_setting_port_attributes[set_port_attr]
+** Getting xstats names (can be polled once and then combined with updated values): link:trex_rpc_server_spec.html#_get_xstat_names[get_port_xstats_names]
+** Getting xstats values: link:trex_rpc_server_spec.html#_get_xstat_values[get_port_xstats_values]
+
+=== fix issues: ===
+
+* link:https://trex-tgn.cisco.com/youtrack/issue/trex-253[trex-253]
+* link:https://trex-tgn.cisco.com/youtrack/issue/trex-212[trex-212]
+* link:https://trex-tgn.cisco.com/youtrack/issue/trex-251[trex-251]
+
+== Release 2.09 ==
+
+* Stateless, split to core algorithm is more accurate and simple see link:trex_stateless.html#_tutorial_field_engine_split_to_core[split_to_core]
+* Add repeatable random instruction see an example link:https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/stl/udp_1pkt_repeat_random.py[stl/udp_1pkt_repeat_random.py] link:cp_stl_docs/api/field_engine.html#stlvmflowvarrepetablerandom[repetable_random] and link:trex_rpc_server_spec.html#_repetable_random[repetable_random_spec]
+* Add TCP/UDP checksum fix instruction see an example link:https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/stl/syn_attack_fix_cs_hw.py[stl/syn_attack_fix_cs_hw.py] link:cp_stl_docs/api/field_engine.html#stlvmfixchecksumhw[fix checksum] and link:trex_rpc_server_spec.html#_fix_checksum_hw[fix_checksum_hw_spec]
+* Improve Stateless Field Engine (FE) performance
+* Support dual mode for push pcap/remote Python API. see here link:cp_stl_docs/api/client_code.html#trex_stl_lib.trex_stl_client.STLClient.push_remote[push_remote] and link:cp_stl_docs/api/client_code.html#trex_stl_lib.trex_stl_client.STLClient.push_pcap[push_pcap] Using this feature pcap can be splited to client/server ports
+* Add infra for L2 emulation support
+
+=== fix issues: ===
+
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-243[trex-243]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-247[trex-247]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-244[trex-244]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-249[trex-249]
+
+== Release 2.08 ==
+
+* Scapy JSON-RPC server for GUI packet crafting, see link:trex_scapy_rpc_server.html[trex_scapy_rpc_server]
+* Client.start Python API supports Core mask - significantly improve the Stateless performance. link:cp_stl_docs/_modules/trex_stl_lib/trex_stl_client.html#STLClient.start[start API], and link:trex_stateless.html#_core_masking_per_interface[core_masking]
+* Upgrade the ./dpdk_setup_ports.py script. It simplifies the way to create first time *optimized* config file (/etc/trex_cfg.yaml). More info at the manual: link:trex_manual.html#_script_for_creating_config_file[Script for creating config file]
+
+[source,bash]
+----
+$sudo ./dpdk_setup_ports.py -t # show the list of ports
+$sudo ./dpdk_setup_ports.py -l # return DPDK interfaces to Linux (if there is proper Linux driver)
+$sudo ./dpdk_setup_ports.py -i # interactive creation of config file
+$sudo ./dpdk_setup_ports.py -c 03:00.0 03:00.1 -o /etc/trex_cfg.yaml # create optimum /etc/trex_cfg.yaml file
+----
+
+* Preliminary Cisco VIC support. Advanced Stateless/Stateful functionality is still not supported.
+* Enforce latest firmware for XL710/X710 (5.04)
+* Add a way to stop/close NICS at TRex termination (link would be down) `-close-at-end`
+* IPv6 XL710 ICMP packets are supported now
+
+=== fix issues: ===
+
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-240[trex-240]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-242[trex-242]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-246[trex-246]
+
+== Release 2.07 ==
+
+* DPDK 16.07
+* ASYNC ZMQ is compressed by default. It improves response time see link:http://trex-tgn.cisco.com/youtrack/issue/trex-232[trex-232]
+** You will need to update the GUI
+* Support Ubuntu 16.01 - Stateful serverr is Python 3.0 and Python 3.5 for ZMQ library
+* XL710/X710 low latency was improved - see link:http://trex-tgn.cisco.com/youtrack/issue/trex-214[trex-214]
+* Support graceful shutdown command
+* Console - support L1 BPS using `-m 10bpsl1` see link:http://trex-tgn.cisco.com/youtrack/issue/trex-230[trex-230]
+* Improve TUI refresh time
+* Support IPV6 latency streams (support is available for all interface types except 82599) see link:trex_stateless.html#_tutorial_per_stream_latency_jitter_packet_errors[IPV6 latency]
+
+[IMPORTANT]
+=====================================
+For XL710/X710 there is a need to upgrade the firmware to 5.04 (or later)
+=====================================
+
+=== fix issues: ===
+
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-214[trex-214]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-223[trex-223]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-226[trex-226]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-224[trex-224]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-235[trex-235]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-236[trex-236]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-238[trex-238]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-233[trex-233]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-231[trex-231]
+
+
+== Release 2.06 ==
+
+* Support APIC-EM scale Stateful VLAN/IP/MAC mapping.
+* TCP SYN Randomization learning support for advanced ASA stateful testing - link:trex_manual.html#_nat_support[here] and link:trex_manual.html#_trex_with_asa_5585[here]
+* Advanced to latest DPDK 16.07RC3 - fix some XL710 driver performance issues
+
+=== fix issues: ===
+
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-229[trex-229]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-227[trex-227]
+
+
+== Release 2.05 ==
+
+
+=== fix issues: ===
+
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-221[trex-221]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-220[trex-220]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-219[trex-219]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-218[trex-218]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-217[trex-217]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-216[trex-216]
+
+
+== Release 2.04 ==
+
+* Watchdog support
+* Ability to export core file
+* Optimized the case of Latency stream, Field Engine and 9K template packets
+
+=== fix issues: ===
+
+* XL710/X710 present high latency with 9K packets link:http://trex-tgn.cisco.com/youtrack/issue/trex-214[trex-214]
+* The latency seq number gets out of sync link:http://trex-tgn.cisco.com/youtrack/issue/trex-215[trex-215]
+* Port/Latency stats should be with FCS link:http://trex-tgn.cisco.com/youtrack/issue/trex-213[trex-213]
+* Stateless Unicode is not accepted for multiplier API see link:https://github.com/cisco-system-traffic-generator/trex-core/issues/15[github-issue15]
+
+
+== Release 2.03 ==
+
+* More accurate stateless latency/more TUI support
+* Speedup DPDK XL710 fdir driver
+
+=== fix issues: ===
+
+* Disconnect issue link:http://trex-tgn.cisco.com/youtrack/issue/trex-210[trex-210]
+
+
+== Release 2.02 ==
+
+* The python latency statistic is compatible to JSON for easy manipulation
+* Add latency minimum value Python API taken from histogram
+
+=== fix issues: ===
+
+* Fix corruption of mbuf in case of with high rate latency stream.
+
+== Release 2.01 ==
+
+* First release of latency/jitter per stream see link:trex_stateless.html#_tutorial_per_stream_latency_jitter_packet_errors[here]
+* Ability to send server side pcap file - unlimited pcap file size see link:/cp_stl_docs/_modules/trex_stl_lib/trex_stl_client.html#STLClient.push_remote[here] and link:trex_stateless.html#_pcap_based_traffic_tutorials[PCAP tutorial]
+* Significatly improve performance for both Stateful and Stateless - in some cases up to x2 due to Scheduler/CPU utilization rewrite
+* CPU utilization estimation is done differently
+* Ability to significatly improve performance for Stateless profile with Field engine (up to x5, 22MPPS) see link:trex_stateless.html#_tutorial_field_engine_significantly_improve_performance[here]
+* Add documentation index link:index.html[index]
+* Fix documentation Table of Content javascript
+* Update Stateless presentation link:http://www.slideshare.net/HanochHaim/trex-realistic-traffic-generator-stateless-support[Statelss presenation]
+* Stateful Python server API - Add support for iterator of remote file for Stateful GUI
+
+=== fix issues: ===
+
+* Performance issue, link:http://trex-tgn.cisco.com/youtrack/issue/trex-207[trex-207]
+* Sporadic timeout on wait_on_traffic() API see link:http://trex-tgn.cisco.com/youtrack/issue/trex-209[trex-209]
+
+== Release 2.00 ==
+
+* Console
+** Support partial port acquire using new CLI switch `-a ACQUIRE` (first phase)
+** Add tx/rx graphs
+* Python API: add an API for reading events as warning/errors
+* HLTAPI support for per stream stats
+* support VALN mode for per stream stats for 82599 using `--vlan` switch at server invocation
+* A peek into TRex stateless GUI version for evaluation still without many features like packet builder, advance packet builder, per stream stats link:https://www.dropbox.com/s/vs9gojtdc5ewv05/setupCiscoTrex1.96-SNAPSHOT.exe?dl=0[TRex Stateless GUI Download]
+** Only pcap file packet builder is supported in this version
+
+image::images/trex_stl_gui.png[title="TRex Stateless GUI",align="left",width=600, link="images/trex_stl_gui.png"]
+
+=== fix issues: ===
+
+* X710/XL710 per stream hardware stats
+** link:http://trex-tgn.cisco.com/youtrack/issue/trex-199[trex-199]
+** Fix issue of RX bytes
+** Fix issue with mbuf leak
+* Packet Memory shortage fix link:http://trex-tgn.cisco.com/youtrack/issue/trex-197[trex-197]
+* Python Examples - move all examples to be 16.0.0.x/48.0.0.x for some refactor
+
+
+== Release 1.99 ==
+
+
+* The Client package includes Console/examples
+* Client API verification mechanism. The client should match the server version range
+
+=== fix issues: ===
+
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-193[trex-193]
+* Python2/Python3 client API hardening
+* Per stream statistics in software hardening - add support for wait on rx packets
+
+
+== Release 1.98 ==
+
+* Minor Console issue
+* [red]*Image is broken* see link:http://trex-tgn.cisco.com/youtrack/issue/trex-193[trex-193]
+
+== Release 1.97 ==
+
+* Support pyATS with Python 3/32bit
+* Per stream statistic supported by software for I350/82559/VXNET3
+* [red]*Image is broken* see link:http://trex-tgn.cisco.com/youtrack/issue/trex-193[trex-193]
+
+== Release 1.96 ==
+
+* Support pyATS/32bit/Python2.x for TCL
+* Traffic profile direction/port directive works see link:draft_trex_stateless.html#_tutorial_advance_traffic_profile[here]
+* Documentation
+** Add Python API documentation link:cp_stl_docs/index.html[here]
+** Add pyATS2.0 support link:cp_stl_docs/index.html[here]
+** Update per stream statistic documentation see link:draft_trex_stateless.html#_tutorial_per_stream_statistics[per stream statistic]
+** Update HLTAPI arguments link:draft_trex_stateless.html#_hlt_supported_arguments_a_id_altapi_support_a[HLTAPI]
+
+=== fix issues: ===
+
+* Per stream statistic - Fix High speed of start/stop of giving zero in statistics
+* Fix E1000 DPDK driver prints with ESXi
+
+
+== Release 1.95 ==
+
+* TUI support per stream stats (press s to get to this window)
+* per stream statistic API examples
+* Add Python API automatic documentation scripts
+* Fix issue with a packet smaller than 64 bytes
+
+=== Known issue
+
+* High speed of start/stop of per stream stats give zero in statistics
+
+
+== Release 1.94 ==
+
+* Fix Python API stop/sync issue. Now TX counters are synced in case of stop API
+* Improve performance of Python API, ~2000 cycles/sec of load/start/stop
+* Add per stream Tx/Rx statistics for XL710/X710 NICS work in flow-director hardware
+
+[source,python]
+----
+class STLS1(object):
+
+ def get_streams (self, direction = 0):
+ return [STLStream(packet =
+ STLPktBuilder(
+ pkt ="stl/yaml/udp_64B_no_crc.pcap"),
+ mode = STLTXCont(pps=10),
+ rx_stats = STLRxStats(user_id = 7)) <1>
+ ]
+----
+<1> Configure this stream to be count on all RX ports as user_id=7
+
+* Add HTLAPI full example (examples `examples/hlt_udp_simple.py`)
+* Add user manual draft for Stateless functionality link:draft_trex_stateless.html[here]
+
+
+== Release 1.93 ==
+
+* Support port attribute API and Console command. See `$portattr -a --prom`
+* Support random seed per Stream attribute - see specification for more info
+* Add more sample/profiles (stl/hlt) from real use cases
+* Enhance Field Engine with new instructions
+* TUI now shows L1 and L2 bandwidth. Console support L1 and L2 and %%
+* Stream rate can be configured with PPS/bps_L1/bps_L2/port_percentage
+* Update Stateless JSON-RPC specification
+* HLT fixes and support split_by variable
+* First phase of per stream rx/tx statistic - XL710/X710 hardware support
+
+=== fix issues: ===
+
+* Fix some typo in Python API stl/example folder
+* Fix Field Engine IPv4 checksum issue with big packet size
+* Fix Field Engine issue with random variables
+* Fix `streams -a` crash
+* Fix X710 issue. Now return speed of 10gb instead of 40gb for Stateless port speed
+
+
+== Release 1.92 ==
+
+** Stream can set static Source/Destination MAC-Address as oppose to the default (TRex port from /etc/trex_config.yaml)
+
+[source,python]
+----
+def create_stream (self):
+ base_pkt = Ether(src="00:00:dd:dd:00:01")/IP()/UDP()
+ pad = max(0, size - len(base_pkt)) * 'x'
+----
+
+** Stream support action_count. Loop of streams can end after action_count number. The push command uses this new feature to import pcap to streams and stop after x iteration.
+
+[source,python]
+----
+STLStream( self_start = False,
+ name ='S2',
+ packet = STLPktBuilder(pkt = base_pkt2/pad),
+ mode = STLTXSingleBurst( pps = 10, total_pkts = 3 ),
+ action_count = 2, # loop 2 times
+ next = 'S0'
+ )
+----
+
+** Support new Field-Engine instructions (variable with step and write with mask). See new sample folder and specification for more info
+
+[source,python]
+----
+def create_stream (self):
+
+ # 2 MPLS label the internal with s=1 (last one)
+ pkt = Ether()/MPLS(label=17,cos=1,s=0,ttl=255)/MPLS(label=0,cos=1,s=1,ttl=12)/IP()/UDP()/('x'*20)
+
+ vm = CTRexScRaw( [ STLVmFlowVar(name="mlabel", min_value=1, max_value=2000, size=2, op="inc"),
+ STLVmWrMaskFlowVar(fv_name="mlabel", pkt_offset= "MPLS:1.label",pkt_cast_size=4, mask=0xFFFFF000,shift=12) # write mask
+ ]
+ )
+----
+
+[source,python]
+----
+ vm = CTRexScRaw( [ STLVmFlowVar(name="mac_src", min_value=1, max_value=30, size=1, op="dec",step=7), # step
+ STLVmWrFlowVar(fv_name="mac_src", pkt_offset= 11)
+ ]
+ )
+----
+
+** More profile samples (native/hlt)
+
+
+== Release 1.91 ==
+
+* Convert Stateless traffic profile to Scapy see `stl/*.py` sample folder
+* Add HLTAPI tests and profile `stl/hlt/*.py`
+* Fix simulator path issue fix
+* The Stateless python library is not self-contained. in `automation/trex_control_plane/stl/` library is `automation/trex_control_plane/stl/trex_stl_lib/` (import trex_stl_lib)
+
+How to run the simulator
+[source,bash]
+----
+./stl-sim -f stl/udp_1pkt_range_clients_split.py -o b.pcap -l 100 -c 2
+----
+
+* Add push command to convert pcap to streams
+
+-------------------
+TRex > push --help
+usage: push [-h] -f FILE [--port PORTS [PORTS ...] | -a] [-d TIME]
+ [-i IPG_USEC] [-s SPEEDUP] [--force]
+
+optional arguments:
+ -h, --help show this help message and exit
+ -f FILE File path to load
+ --port PORTS [PORTS ...]
+ A list of ports on which to apply the command
+ -a Set this flag to apply the command on all available
+ ports
+ -d TIME Set duration time for job.
+ -i IPG_USEC, --ipg IPG_USEC
+ IPG value in usec between packets. default will be
+ from the pcap
+ -s SPEEDUP, --speedup SPEEDUP
+ Factor to accelerate the injection. effectively means
+ IPG = IPG / SPEEDUP
+ --force Set if you want to stop active ports before appyling
+ command.
+TRex >push -f cap2/dns.pcap --port 0 -i 10
+-------------------
+
+
+
+== Release 1.90 ==
+
+* Missing file in the pkg
+
+== Release 1.89 ==
+
+* Integrate Scapy as a packet builder see `stl/profiles` folder
+* Improve Python API, samples can be seen link:https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/api/stl/examples[here]
+* Add Stateless simulator into the package
+
+Example how to run
+[source,bash]
+----
+./stl-sim -f stl/profiles/udp_1pkt.py -l 10 -o a.pcap #<1>
+./stl-sim -f stl/profiles/udp_1pkt_tuple_gen.py -l 20 -o a.pcap #<2>
+./stl-sim -f stl/profiles/imix.py -l 100 -o a.pcap --json #<3>
+----
+<1> Limit the number of packets to 10
+<2> Tuple generator example
+<3> imix
+
+The simulator takes Stateless profile,YAML or Py and output pcap file or json
+
+* Console can load the new Python profile
+
+[source,bash]
+----
+TRex > start -f stl/profiles/udp_1pkt.py -a -m 1mbps
+----
+
+* Basic Python HLTAPI support
+
+=== fix issues: ===
+
+* Dependent streams (e.g. `stl/burst_1000_pkt.yaml`) can be loaded
+
+== Release 1.88 ==
+
+* Add the Python API to the package
+* Remove mock support
+
+== Release 1.87 ==
+
+* Fix some 82599 ierror in case of high rate
+* First Stateless API examples under api folder (not part of the package)
+
+
+== Release 1.86 ==
+
+* NAT Cisco ASA support
+** Add support for learning using TCP-ACK field see more here link:trex_manual.html#_nat_support[here] and link:trex_manual.html#_trex_with_asa_5585[here]
+* More stateless support
+
+== Release 1.85 ==
+
+* Upgrade to DPDK 2.2.0
+** Some XL710/X710 NIC phy issues solved
+** VMXNET3 driver is optimized
+** Cisco VIC should be supported, not tested yet
+* Jumbo packet size is supported for 1/10/40 Intel NIC up to 9K for both stateless and stateful
+* youTrack is public now, can be seen here link:http://trex-tgn.cisco.com/youtrack[here]
+* More stateless support
+** Support random packet size trim instruction - see stl/udp_rand_size_9k.yaml for an example
+** Move Python Regression to trex-core
+** Add Coverity scripts
+** Console/Python API can be call from Cisco CEL now (ZMQ Python library is compiled to an old glibc)
+** Add simulator for stateless
+
+=== fix issues: ===
+
+* The infamous DPDK error is not seen in case of a wrong core argument see here link:http://trex-tgn.cisco.com/youtrack/issue/trex-147[trex-147]
+
+== Release 1.84 ==
+
+* more stateless support
+** Add splitter range support see "split_by_var" in style/imix_1pkt_vm. yaml
+** Add more samples see stl/syn_attack_sample.yaml. Improve random performance
+** more improvement with TUI window
+
+
+== Release 1.83 ==
+
+* more stateless support
+** Add basic Packet Field engine see stl/imin_1pkt_vm.yaml
+** some improvement with TUI window. Can be run in parallel with --tui option
+
+== Release 1.82 ==
+
+* more stateless support
+** console stats/tui function works now
+** R/W support. only one client has R/W capability
+* XL710/X710 support ICMP filter
+
+=== fix issues: ===
+
+* link:http://trex-tgn.cisco.com/youtrack/trex-110[trex-110]
+
+
+== Release 1.81 ==
+
+* more stateless support and fixes
+** change the JSON-RPC result format
+* Support for specifying different modes for the packets used for latency measurement. Details link:trex_manual.html#_measure_jitter_latency[here].
+
+=== fix issues: ===
+
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-149[trex-149]
+
+== Release 1.80 ==
+
+* more stateless support
+** All type of streams are supported (Continues/Burst/Multi-burst)
+** Stream can call to other streams
+** start/stop/pause/resume work from the Console
+** -m[rate] is supported for example -m10gbps or -m10kpps from console
+** update XL710 installation support
+
+== Release 1.79 ==
+
+* Initial support for stateless
+** Only continues streams are supported
+** more info how to enable the interactive shell link:trex_console.html[here]
+
+== Release 1.78 ==
+
+* some clean up in tuple generator
+* trex stateles console works with trex-mock
+
+=== fix issues: ===
+
+Python API fixup see here
+
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-126[trex-126]
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-123[trex-122]
+
+Check for 64bit Kernel
+
+* link:http://trex-tgn.cisco.com/youtrack/issue/trex-123[trex-123]
+
+== Release 1.77 ==
+
+* improve tuple generator capability now it is more flexiable see more link:trex_manual.html#_clients_servers_ip_allocation_scheme[here]
+
+== Release 1.76 ==
+
+=== fix issues: ===
+
+* minor pcap loader issues
+* plugin cleanup
+
+
+== Release 1.75 ==
+
+=== fix issues: ===
+
+* First version that works from GitHub/Git - init script are in the output package
+
+== Release 1.72 ==
+
+
diff --git a/doc/symbols.lang b/doc/symbols.lang
new file mode 100755
index 00000000..38ac4e1c
--- /dev/null
+++ b/doc/symbols.lang
@@ -0,0 +1,5 @@
+co_symbol = "<1>","<2>","<3>","<4>","<5>","<6>","<7>","<8>",
+ "<9>","<10>","<11>","<12>","<13>","<14>","<15>"
+symbol = "~","!","%","^","*","(",")","-","+","=","[",
+ "]","\\",":",";",",",".","/","?","&","<",">","\|"
+
diff --git a/doc/trex_book-docinfo.html b/doc/trex_book-docinfo.html
new file mode 100755
index 00000000..c050287b
--- /dev/null
+++ b/doc/trex_book-docinfo.html
@@ -0,0 +1,22 @@
+
+<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+
+<script src="my_chart.js"></script>
+
+<style>
+.axis path,
+.axis line {
+ fill: none;
+ stroke: #000;
+ shape-rendering: crispEdges;
+}
+
+.dot {
+ stroke: #000;
+}
+</style>
+
+
+
+
+
diff --git a/doc/trex_book.asciidoc b/doc/trex_book.asciidoc
new file mode 100755
index 00000000..2d35787a
--- /dev/null
+++ b/doc/trex_book.asciidoc
@@ -0,0 +1,2027 @@
+TRex
+====
+:author: hhaim
+:email: <hhaim@cisco.com>
+:revnumber: 2.1
+:quotes.++:
+:numbered:
+:web_server_url: http://trex-tgn.cisco.com/trex
+:local_web_server_url: csi-wiki-01:8181/trex
+:toclevels: 4
+
+include::trex_ga.asciidoc[]
+
+
+== Introduction
+
+=== A word on traffic generators
+
+Traditionally, routers have been tested using commercial traffic generators, while performance
+typically has been measured using packets per second (PPS) metrics. As router functionality and
+services became more complex, stateful traffic generators now need to provide more realistic traffic scenarios.
+
+Advantages of realistic traffic generators:
+
+* Accurate performance metrics.
+* Discovering bottlenecks in realistic traffic scenarios.
+
+==== Current Challenges:
+
+* *Cost*: Commercial stateful traffic generators are very expensive.
+* *Scale*: Bandwidth does not scale up well with feature complexity.
+* *Standardization*: Lack of standardization of traffic patterns and methodologies.
+* *Flexibility*: Commercial tools do not allow agility when flexibility and changes are needed.
+
+==== Implications
+
+* High capital expenditure (capex) spent by different teams.
+* Testing in low scale and extrapolation became a common practice. This is non-ideal and fails to indicate bottlenecks that appear in real-world scenarios.
+* Teams use different benchmark methodologies, so results are not standardized.
+* Delays in development and testing due to dependence on testing tool features.
+* Resource and effort investment in developing different ad hoc tools and test methodologies.
+
+=== Overview of TRex
+
+TRex addresses these problems through an innovative and extendable software implementation and by leveraging standard and open software and x86/UCS hardware.
+
+* Generates and analyzes L4-7 traffic. In one package, provides capabilities of commercial L7 tools.
+* Stateful traffic generator based on pre-processing and smart replay of real traffic templates.
+* Generates and *amplifies* both client and server side traffic.
+* Customized functionality can be added.
+* Scales to 200Gb/sec for one UCS (using Intel 40Gb/sec NICs).
+* Low cost.
+* Self-contained package that can be easily installed and deployed.
+* Virtual interface support enables TRex to be used in a fully virtual environment without physical NICs. Example use cases:
+** Amazon AWS
+** Cisco LaaS
+// Which LaaS is this? Location as a service? Linux?
+** TRex on your laptop
+
+
+
+.TRex Hardware
+[options="header",cols="1^,1^"]
+|=================
+|Cisco UCS Platform | Intel NIC
+| image:images/ucs200_2.png[title="generator"] | image:images/Intel520.png[title="generator"]
+|=================
+
+=== Purpose of this guide
+
+This guide explains the use of TRex internals and the use of TRex together with Cisco ASR1000 Series routers. The examples illustrate novel traffic generation techniques made possible by TRex.
+
+== Download and installation
+
+=== Hardware recommendations
+
+TRex operates in a Linux application environment, interacting with Linux kernel modules.
+TRex curretly works on x86 architecture and can operate well on Cisco UCS hardware. The following platforms have been tested and are recommended for operating TRex.
+
+[NOTE]
+=====================================
+ A high-end UCS platform is not required for operating TRex in its current version, but may be required for future versions.
+=====================================
+
+[NOTE]
+=====================================
+ Not all supported DPDK interfaces are supported by TRex
+=====================================
+
+
+.Preferred UCS hardware
+[options="header",cols="1,3"]
+|=================
+| UCS Type | Comments
+| UCS C220 M3/M4 | *Preferred Low-End*. Supports up to 40Gb/sec with 540-D2. With newer Intel NIC (recommended), supports 80Gb/sec with 1RU. See table below describing components.
+| UCS C200| Early UCS model.
+| UCS C210 M2 | Supports up to 40Gb/sec PCIe3.0.
+| UCS C240 M3/M4 | *Preferred, High-End* Supports up to 200Gb/sec. 6x XL710 NICS (PCIex8) or 2xFM10K (PCIex16). See table below describing components.
+| UCS C260M2 | Supports up to 30Gb/sec (limited by V2 PCIe).
+|=================
+
+.Low-End UCS C220 M4 - Internal components
+[options="header",cols="1,2",width="60%"]
+|=================
+| Components | Details
+| CPU | 2x E5-2620 @ 2.0 GHz.
+| CPU Configuration | 2-Socket CPU configurations (also works with 1 CPU).
+| Memory | 2x4 banks f.or each CPU. Total of 32GB in 8 banks.
+| RAID | No RAID.
+|=================
+
+.High-End C240 M4 - Internal components
+[options="header",cols="1,2",width="60%"]
+|=================
+| Components | Details
+| CPU | 2x E5-2667 @ 3.20 GHz.
+| PCIe | 1x Riser PCI expansion card option A PID UCSC-PCI-1A-240M4 enables 2 PCIex16.
+| CPU Configuration | 2-Socket CPU configurations (also works with 1 CPU).
+| Memory | 2x4 banks for each CPU. Total of 32GB in 8 banks.
+| RAID | No RAID.
+| Riser 1/2 | both left and right should support x16 PCIe. Right (Riser1) should be from option A x16 and Left (Riser2) should be x16. need to order both
+|=================
+
+.Supported NICs
+[options="header",cols="1,1,2",width="50%"]
+|=================
+| Bandwidth | Chipset | Example
+| 1Gb/sec | Intel I350 | Intel 4x1GE 350-T4 NIC
+| 10Gb/sec | Intel 82599| Cisco part ID:N2XX-AIPCI01 Intel x520-D2, Intel X520 Dual Port 10Gb SFP+ Adapter
+| 10Gb/sec | Intel X710 | Cisco part ID:UCSC-PCIE-IQ10GF link:https://en.wikipedia.org/wiki/Small_form-factor_pluggable_transceiver[SFP+], *Preferred* support per stream stats in hardware link:http://www.silicom-usa.com/PE310G4i71L_Quad_Port_Fiber_SFP+_10_Gigabit_Ethernet_PCI_Express_Server_Adapter_49[Silicom PE310G4i71L]
+| 40Gb/sec | Intel XL710 | Cisco part ID:UCSC-PCIE-ID40GF, link:https://en.wikipedia.org/wiki/QSFP[QSFP+] (copper/optical)
+| 100Gb/sec | Intel Intel FM10420 | QSFP28, by Silicom link:http://www.silicom-usa.com/100_Gigabit_Dual_Port_Fiber_Ethernet_PCI_Express_PE3100G2DQiR_96[Silicom PE3100G2DQiR_96] (*in development*)
+| VMXNET / +
+VMXNET3 (see notes) | VMware paravirtualized | Connect using VMware vSwitch
+| E1000 | paravirtualized | VMware/KVM/VirtualBox
+| Virtio | paravirtualized | KVM
+|=================
+
+// in table above, is it correct to list "paravirtualized" as chipset? Also, what is QSFP28? It does not appear on the lined URL. Clarify: is Intel X710 the preferred NIC?
+
+.SFP+ support
+[options="header",cols="2,1,1,1",width="70%"]
+|=================
+| link:https://en.wikipedia.org/wiki/Small_form-factor_pluggable_transceiver[SFP+] | Intel Ethernet Converged X710-DAX | Silicom link:http://www.silicom-usa.com/PE310G4i71L_Quad_Port_Fiber_SFP+_10_Gigabit_Ethernet_PCI_Express_Server_Adapter_49[PE310G4i71L] (Open optic) | 82599EB 10-Gigabit
+| link:http://www.cisco.com/c/en/us/products/collateral/interfaces-modules/transceiver-modules/data_sheet_c78-455693.html[Cisco SFP-10G-SR] | Does not work | [green]*works* | [green]*works*
+| link:http://www.cisco.com/c/en/us/products/collateral/interfaces-modules/transceiver-modules/data_sheet_c78-455693.html[Cisco SFP-10G-LR] | Does not work | [green]*works* | [green]*works*
+| link:http://www.cisco.com/c/en/us/products/collateral/interfaces-modules/transceiver-modules/data_sheet_c78-455693.html[Cisco SFP-H10GB-CU1M]| [green]*works* | [green]*works* | [green]*works*
+| link:http://www.cisco.com/c/en/us/products/collateral/interfaces-modules/transceiver-modules/data_sheet_c78-455693.html[Cisco SFP-10G-AOC1M] | [green]*works* | [green]*works* | [green]*works*
+|=================
+
+[NOTE]
+=====================================
+ Intel X710 NIC (example: FH X710DA4FHBLK) operates *only* with Intel SFP+. For open optic, use the link:http://www.silicom-usa.com/PE310G4i71L_Quad_Port_Fiber_SFP+_10_Gigabit_Ethernet_PCI_Express_Server_Adapter_49[Silicom PE310G4i71L] NIC.
+=====================================
+
+// clarify above table and note
+
+.XL710 NIC base QSFP+ support
+[options="header",cols="1,1,1",width="90%"]
+|=================
+| link:https://en.wikipedia.org/wiki/QSFP[QSFP+] | Intel Ethernet Converged XL710-QDAX | Silicom link:http://www.silicom-usa.com/Dual_Port_Fiber_40_Gigabit_Ethernet_PCI_Express_Server_Adapter_PE340G2Qi71_83[PE340G2Qi71] Open optic
+| QSFP+ SR4 optics | APPROVED OPTICS [green]*works*, Cisco QSFP-40G-SR4-S does *not* work | Cisco QSFP-40G-SR4-S [green]*works*
+| QSFP+ LR-4 Optics | APPROVED OPTICS [green]*works*, Cisco QSFP-40G-LR4-S does *not* work | Cisco QSFP-40G-LR4-S [green]*works*
+| QSFP Active Optical Cables (AoC) | Cisco QSFP-H40G-AOC [green]*works* | Cisco QSFP-H40G-AOC [green]*works*
+| QSFP+ Intel Ethernet Modular Optics | N/A | N/A
+| QSFP+ DA twin-ax cables | N/A | N/A
+| Active QSFP+ Copper Cables | Cisco QSFP-4SFP10G-CU [green]*works* | Cisco QSFP-4SFP10G-CU [green]*works*
+|=================
+
+[NOTE]
+=====================================
+ For Intel XL710 NICs, Cisco SR4/LR QSFP+ does not operate. Use Silicom with Open Optic.
+=====================================
+
+// clarify above table and note. let's discuss.
+
+.FM10K QSFP28 support
+[options="header",cols="1,1",width="70%"]
+|=================
+| QSFP28 | Example
+| todo | todo
+|=================
+
+// do we want to show "todo"? maybe "pending"
+
+
+[IMPORTANT]
+=====================================
+* Intel SFP+ 10Gb/sec is the only one supported by default on the standard Linux driver. TRex also supports Cisco 10Gb/sec SFP+.
+// above, replace "only one" with "only mode"?
+* For operating high speed throughput (example: several Intel XL710 40Gb/sec), use different link:https://en.wikipedia.org/wiki/Non-uniform_memory_access[NUMA] nodes for different NICs. +
+ To verify NUMA and NIC topology: `lstopo (yum install hwloc)` +
+ To display CPU info, including NUMA node: `lscpu` +
+ NUMA usage xref:numa-example[example]
+* For Intel XL710 NICs, verify that the NVM is v5.04 . xref:xl710-firmware[Info].
+** `> sudo ./t-rex-64 -f cap2/dns.yaml -d 0 *-v 6* --nc | grep NVM` +
+ `PMD: FW 5.0 API 1.5 NVM 05.00.04 eetrack 800013fc`
+=====================================
+
+// above, maybe rename the bullet points "NIC usage notes"? should we create a subsection for NICs? Maybe it would be under "2.1 Hardware recommendations" as a subsection.
+
+
+.Sample order for recommended low-end Cisco UCSC-C220-M3S with 4x10Gb ports
+[options="header",cols="1,1",width="70%"]
+|=================
+| Component | Quantity
+| UCSC-C220-M3S | 1
+| UCS-CPU-E5-2650 | 2
+| UCS-MR-1X041RY-A | 8
+| A03-D500GC3 | 1
+| N2XX-AIPCI01 | 2
+| UCSC-PSU-650W | 1
+| SFS-250V-10A-IS | 1
+| UCSC-CMA1 | 1
+| UCSC-HS-C220M3 | 2
+| N20-BBLKD | 7
+| UCSC-PSU-BLKP | 1
+| UCSC-RAIL1 | 1
+|=================
+
+// should table above say "low-end Cisco UCS C220 M3S" instead of "low-end USCS-C220-M3S"?
+
+NOTE: Purchase the 10Gb/sec SFP+ separately. Cisco would be fine with TRex (but not for plain Linux driver).
+// does note above mean "TRex operates with 10Gb/sec SFP+ components, but plain Linux does not provide drivers."? if so, how does purchasing separately solve this? where do they get drivers?
+
+=== Installing OS
+
+==== Supported versions
+
+Supported Linux versions:
+
+* Fedora 20-23, 64-bit kernel (not 32-bit)
+* Ubuntu 14.04.1 LTS, 64-bit kernel (not 32-bit)
+* Ubuntu 16.xx LTS, 64-bit kernel (not 32-bit)
+
+NOTE: Additional OS version may be supported by compiling the necessary drivers.
+
+To check whether a kernel is 64-bit, verify that the ouput of the following command is `x86_64`.
+
+[source,bash]
+----
+$uname -m
+x86_64
+----
+
+
+==== Download Linux
+
+ISO images for supported Linux releases can be downloaded from:
+
+.Supported Linux ISO image links
+[options="header",cols="1^,2^",width="50%"]
+|======================================
+| Distribution | SHA256 Checksum
+| link:http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/20/Fedora/x86_64/iso/Fedora-20-x86_64-DVD.iso[Fedora 20]
+ | link:http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/20/Fedora/x86_64/iso/Fedora-20-x86_64-CHECKSUM[Fedora 20 CHECKSUM]
+| link:http://fedora-mirror01.rbc.ru/pub/fedora/linux/releases/21/Server/x86_64/iso/Fedora-Server-DVD-x86_64-21.iso[Fedora 21]
+ | link:http://fedora-mirror01.rbc.ru/pub/fedora/linux/releases/21/Server/x86_64/iso/Fedora-Server-21-x86_64-CHECKSUM[Fedora 21 CHECKSUM]
+| link:http://old-releases.ubuntu.com/releases/14.04.1/ubuntu-14.04-desktop-amd64.iso[Ubuntu 14.04.1]
+ | http://old-releases.ubuntu.com/releases/14.04.1/SHA256SUMS[Ubuntu 14.04* CHECKSUMs]
+| link:http://releases.ubuntu.com/16.04.1/ubuntu-16.04.1-server-amd64.iso[Ubuntu 16.04.1]
+ | http://releases.ubuntu.com/16.04.1/SHA256SUMS[Ubuntu 16.04* CHECKSUMs]
+
+|======================================
+
+For Fedora downloads...
+
+* Select a mirror close to your location: +
+https://admin.fedoraproject.org/mirrormanager/mirrors/Fedora +
+Choose: "Fedora Linux http" -> releases -> <version number> -> Server -> x86_64 -> iso -> Fedora-Server-DVD-x86_64-<version number>.iso
+
+* Verify the checksum of the downloaded file matches the linked checksum values with the `sha256sum` command. Example:
+
+[source,bash]
+----
+$sha256sum Fedora-18-x86_64-DVD.iso
+91c5f0aca391acf76a047e284144f90d66d3d5f5dcd26b01f368a43236832c03 #<1>
+----
+<1> Should be equal to the link:https://en.wikipedia.org/wiki/SHA-2[SHA-256] values described in the linked checksum files.
+
+
+==== Install Linux
+
+Ask your lab admin to install the Linux using CIMC, assign an IP, and set the DNS. Request the sudo or super user password to enable you to ping and SSH.
+
+xref:fedora21_example[Example of installing Fedora 21 Server]
+
+[NOTE]
+=====================================
+ * To use TRex, you should have sudo on the machine or the root password.
+ * Upgrading the linux Kernel using `yum upgrade` requires building the TRex drivers.
+ * In Ubuntu 16, auto-updater is enabled by default. It's advised to turn it off as with update of Kernel need to compile again the DPDK .ko file. +
+Command to remove it: +
+ > sudo apt-get remove unattended-upgrades
+=====================================
+
+==== Verify Intel NIC installation
+
+Use `lspci` to verify the NIC installation.
+
+Example 4x 10Gb/sec TRex configuration (see output below):
+
+* I350 management port
+
+* 4x Intel Ethernet Converged Network Adapter model x520-D2 (82599 chipset)
+
+[source,bash]
+----
+$[root@trex]lspci | grep Ethernet
+01:00.0 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01) #<1>
+01:00.1 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01) #<2>
+03:00.0 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01) #<3>
+03:00.1 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01)
+82:00.0 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01)
+82:00.1 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01)
+----
+<1> Management port
+<2> CIMC port
+<3> 10Gb/sec traffic ports (Intel 82599EB)
+
+=== Obtaining the TRex package
+
+Connect using `ssh` to the TRex machine and execute the commands described below.
+
+NOTE: Prerequisite: *$WEB_URL* is *{web_server_url}* or *{local_web_server_url}* (Cisco internal)
+
+Latest release:
+[source,bash]
+----
+$mkdir trex
+$cd trex
+$wget --no-cache $WEB_URL/release/latest
+$tar -xzvf latest
+----
+
+
+Bleeding edge version:
+[source,bash]
+----
+$wget --no-cache $WEB_URL/release/be_latest
+----
+
+To obtain a specific version, do the following:
+[source,bash]
+----
+$wget --no-cache $WEB_URL/release/vX.XX.tar.gz #<1>
+----
+
+<1> X.XX = Version number
+
+== First time Running
+
+=== Configuring for loopback
+
+Before connecting TRex to your DUT, it is strongly advised to verify that TRex and the NICs work correctly in loopback. +
+To get best performance, it is advised to loopback interfaces on the same NUMA (controlled by the same physical processor). If you do not know how to check this, you can ignore this advice for now. +
+
+[NOTE]
+=====================================================================
+If you are using 10Gbs NIC based on Intel 520-D2 NICs, and you loopback ports on the same NIC, using SFP+, it might not sync, and you will fail to get link up. +
+We checked many types of SFP+ (Intel/Cisco/SR/LR) and it worked for us. +
+If you still encounter link issues, you can either try to loopback interfaces from different NICs, or use link:http://www.fiberopticshare.com/tag/cisco-10g-twinax[Cisco twinax copper cable].
+=====================================================================
+
+.Loopback example
+image:images/loopback_example.png[title="Loopback example"]
+
+==== Identify the ports
+
+[source,bash]
+----
+ $>sudo ./dpdk_setup_ports.py -s
+
+ Network devices using DPDK-compatible driver
+ ============================================
+
+ Network devices using kernel driver
+ ===================================
+ 0000:03:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv= unused=ixgb #<1>
+ 0000:03:00.1 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv= unused=ixgb
+ 0000:13:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv= unused=ixgb
+ 0000:13:00.1 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv= unused=ixgb
+ 0000:02:00.0 '82545EM Gigabit Ethernet Controller (Copper)' if=eth2 drv=e1000 unused=igb_uio *Active* #<2>
+
+ Other network devices
+ =====================
+ <none>
+----
+
+<1> If you did not run any DPDK application, you will see list of interfaces binded to the kernel, or not binded at all.
+<2> Interface marked as 'active' is the one used by your ssh connection. *Never* put it in TRex config file.
+
+Choose ports to use and follow the instructions in the next section to create configuration file.
+
+==== Creating minimum configuration file
+
+Default configuration file name is: `/etc/trex_cfg.yaml`.
+
+You can copy basic configuration file from cfg folder
+
+[source,bash]
+----
+$cp cfg/simple_cfg.yaml /etc/trex_cfg.yaml
+----
+
+Then, edit the configuration file and put your interface's and IP addresses details.
+
+Example:
+
+[source,bash]
+----
+<none>
+- port_limit : 2
+ version : 2
+#List of interfaces. Change to suit your setup. Use ./dpdk_setup_ports.py -s to see available options
+interfaces : ["03:00.0", "03:00.1"] #<1>
+ port_info : # Port IPs. Change to suit your needs. In case of loopback, you can leave as is.
+ - ip : 1.1.1.1
+ default_gw : 2.2.2.2
+ - ip : 2.2.2.2
+ default_gw : 1.1.1.1
+----
+<1> You need to edit this line to match the interfaces you are using.
+Notice that all NICs you are using should have the same type. You cannot mix different NIC types in one config file. For more info, see link:http://trex-tgn.cisco.com/youtrack/issue/trex-201[trex-201].
+
+You can find xref:trex_config[here] full list of configuration file options.
+
+=== Script for creating config file
+
+To help starting with basic configuration file that suits your needs, there a script that can automate this process.
+The script helps you getting started, and you can then edit the file and add advanced options from xref:trex_config[here]
+if needed. +
+There are two ways to run the script. Interactively (script will pormpt you for parameters), or providing all parameters
+using command line options.
+
+==== Interactive mode
+
+[source,bash]
+----
+sudo ./dpdk_setup_ports.py -i
+----
+
+You will see a list of available interfaces with their related information +
+Just follow the instructions to get basic config file.
+
+==== Specifying input arguments using command line options
+
+First, run this command to see the list of all interfaces and their related information:
+
+[source,bash]
+----
+sudo ./dpdk_setup_ports.py -t
+----
+
+* In case of *Loopback* and/or only *L1-L2 Switches* on the way, you do not need to provide IPs or destination MACs. +
+The script Will assume the following interface connections: 0&#8596;1, 2&#8596;3 etc. +
+Just run:
+
+[source,bash]
+----
+sudo ./dpdk_setup_ports.py -c <TRex interface 0> <TRex interface 1> ...
+----
+
+* In case of *Router* (or other next hop device, such as *L3 Switch*), you should specify the TRex IPs and default gateways, or
+MACs of the router as described below.
+
+.Additional arguments to creating script (dpdk_setup_ports.py -c)
+[options="header",cols="2,5,3",width="100%"]
+|=================
+| Arg | Description | Example
+| -c | Create a configuration file by specified interfaces (PCI address or Linux names: eth1 etc.) | -c 03:00.1 eth1 eth4 84:00.0
+| --dump | Dump created config to screen. |
+| -o | Output the config to this file. | -o /etc/trex_cfg.yaml
+| --dest-macs | Destination MACs to be used per each interface. Specify this option if you want MAC based config instead of IP based one. You must not set it together with --ip and --def_gw | --dest-macs 11:11:11:11:11:11 22:22:22:22:22:22
+| --ip | List of IPs to use for each interface. If this option and --dest-macs is not specified, script assumes loopback connections (0&#8596;1, 2&#8596;3 etc.) | --ip 1.2.3.4 5.6.7.8
+|--def-gw | List of default gateways to use for each interface. If --ip given, you must provide --def_gw as well | --def-gw 3.4.5.6 7.8.9.10
+| --ci | Cores include: White list of cores to use. Make sure there is enough for each NUMA. | --ci 0 2 4 5 6
+| --ce | Cores exclude: Black list of cores to exclude. Make sure there will be enough for each NUMA. | --ci 10 11 12
+| --no-ht | No HyperThreading: Use only one thread of each Core in created config yaml. |
+| --prefix | Advanced option: prefix to be used in TRex config in case of parallel instances. | --prefix first_instance
+| --zmq-pub-port | Advanced option: ZMQ Publisher port to be used in TRex config in case of parallel instances. | --zmq-pub-port 4000
+| --zmq-rpc-port | Advanced option: ZMQ RPC port to be used in TRex config in case of parallel instances. | --zmq-rpc-port
+| --ignore-numa | Advanced option: Ignore NUMAs for config creation. Use this option only if you have to, as it might reduce performance. For example, if you have pair of interfaces at different NUMAs |
+|=================
+
+=== Configuring ESXi for running TRex
+
+To get best performance, it is advised to run TRex on bare metal hardware, and not use any kind of VM.
+Bandwidth on VM might be limited, and IPv6 might not be fully supported.
+Having said that, there are sometimes benefits for running on VM. +
+These include: +
+ * Virtual NICs can be used to bridge between TRex and NICs not supported by TRex. +
+ * If you already have VM installed, and do not require high performance. +
+
+1. Click the host machine, enter Configuration -> Networking.
+
+a. One of the NICs should be connected to the main vSwitch network to get an "outside" connection, for the TRex client and ssh: +
+image:images/vSwitch_main.png[title="vSwitch_main"]
+
+b. Other NICs that are used for TRex traffic should be in distinguish vSwitch: +
+image:images/vSwitch_loopback.png[title="vSwitch_loopback"]
+
+2. Right-click guest machine -> Edit settings -> Ensure the NICs are set to their networks: +
+image:images/vSwitch_networks.png[title="vSwitch_networks"]
+
+[NOTE]
+=====================================================================
+Before version 2.10, the following command did not function as expected:
+[subs="quotes"]
+....
+sudo ./t-rex-64 -f cap2/dns.yaml *--lm 1 --lo* -l 1000 -d 100
+....
+The vSwitch did not "know" where to route the packet. Was solved on version 2.10 when TRex started to support ARP.
+=====================================================================
+
+* Pass-through is the way to use directly the NICs from host machine inside the VM. Has no limitations except the NIC/hardware itself. The only difference via bare-metal OS is occasional spikes of latency (~10ms). Passthrough settings cannot be saved to OVA.
+
+1. Click on the host machine. Enter Configuration -> Advanced settings -> Edit. Mark the desired NICs. Reboot the ESXi to apply. +
+image:images/passthrough_marking.png[title="passthrough_marking"]
+
+2. Right click on guest machine. Edit settings -> Add -> *PCI device* -> Choose the NICs one by one. +
+image:images/passthrough_adding.png[title="passthrough_adding"]
+
+=== Configuring for running with router (or other L3 device) as DUT
+
+You can follow link:trex_config_guide.html[this] presentation for an example of how to configure router as DUT.
+
+=== Running TRex
+
+When all is set, use the following command to start basic TRex run for 10 seconds
+(it will use the default config file name /etc/trex_cfg.yaml):
+[source,bash]
+----
+$sudo ./t-rex-64 -f cap2/dns.yaml -c 4 -m 1 -d 10 -l 1000
+----
+
+If successful, the output will be similar to the following:
+
+[source,python]
+----
+$ sudo ./t-rex-64 -f cap2/dns.yaml -d 10 -l 1000
+Starting TRex 2.09 please wait ...
+zmq publisher at: tcp://*:4500
+ number of ports found : 4
+ port : 0
+ ------------
+ link : link : Link Up - speed 10000 Mbps - full-duplex <1>
+ promiscuous : 0
+ port : 1
+ ------------
+ link : link : Link Up - speed 10000 Mbps - full-duplex
+ promiscuous : 0
+ port : 2
+ ------------
+ link : link : Link Up - speed 10000 Mbps - full-duplex
+ promiscuous : 0
+ port : 3
+ ------------
+ link : link : Link Up - speed 10000 Mbps - full-duplex
+ promiscuous : 0
+
+
+ -Per port stats table
+ ports | 0 | 1 | 2 | 3
+ -------------------------------------------------------------------------------------
+ opackets | 1003 | 1003 | 1002 | 1002
+ obytes | 66213 | 66229 | 66132 | 66132
+ ipackets | 1003 | 1003 | 1002 | 1002
+ ibytes | 66225 | 66209 | 66132 | 66132
+ ierrors | 0 | 0 | 0 | 0
+ oerrors | 0 | 0 | 0 | 0
+ Tx Bw | 217.09 Kbps | 217.14 Kbps | 216.83 Kbps | 216.83 Kbps
+
+ -Global stats enabled
+ Cpu Utilization : 0.0 % <2> 29.7 Gb/core <3>
+ Platform_factor : 1.0
+ Total-Tx : 867.89 Kbps <4>
+ Total-Rx : 867.86 Kbps <5>
+ Total-PPS : 1.64 Kpps
+ Total-CPS : 0.50 cps
+
+ Expected-PPS : 2.00 pps <6>
+ Expected-CPS : 1.00 cps <7>
+ Expected-BPS : 1.36 Kbps <8>
+
+ Active-flows : 0 <9> Clients : 510 Socket-util : 0.0000 %
+ Open-flows : 1 <10> Servers : 254 Socket : 1 Socket/Clients : 0.0
+ drop-rate : 0.00 bps <11>
+ current time : 5.3 sec
+ test duration : 94.7 sec
+
+ -Latency stats enabled
+ Cpu Utilization : 0.2 % <12>
+ if| tx_ok , rx_ok , rx ,error, average , max , Jitter , max window
+ | , , check, , latency(usec),latency (usec) ,(usec) ,
+ --------------------------------------------------------------------------------------------------
+ 0 | 1002, 1002, 0, 0, 51 , 69, 0 | 0 69 67 <13>
+ 1 | 1002, 1002, 0, 0, 53 , 196, 0 | 0 196 53
+ 2 | 1002, 1002, 0, 0, 54 , 71, 0 | 0 71 69
+ 3 | 1002, 1002, 0, 0, 53 , 193, 0 | 0 193 52
+----
+<1> Link must be up for TRex to work.
+<2> Average CPU utilization of transmitters threads. For best results it should be lower than 80%.
+<3> Gb/sec generated per core of DP. Higher is better.
+<4> Total Tx must be the same as Rx at the end of the run
+<5> Total Rx must be the same as Tx at the end of the run
+<6> Expected number of packets per second (calculated without latency packets).
+<7> Expected number of connections per second (calculated without latency packets).
+<8> Expected number of bits per second (calculated without latency packets).
+<9> Number of TRex active "flows". Could be different than the number of router flows, due to aging issues. Usualy the TRex number of active flows is much lower than that of the router because the router ages flows slower.
+<10> Total number of TRex flows opened since startup (including active ones, and ones already closed).
+<11> Drop rate.
+<12> Rx and latency thread CPU utilization.
+<13> Tx_ok on port 0 should equal Rx_ok on port 1, and vice versa.
+
+More statistics information:
+
+*socket*:: Same as the active flows.
+
+*Socket/Clients*:: Average of active flows per client, calculated as active_flows/#clients.
+
+*Socket-util*:: Estimation of number of L4 ports (sockets) used per client IP. This is approximately (100*active_flows/#clients)/64K, calculated as (average active flows per client*100/64K). Utilization of more than 50% means that TRex is generating too many flows per single client, and that more clients must be added in the generator config.
+// clarify above, especially the formula
+
+*Max window*:: Momentary maximum latency for a time window of 500 msec. There are few numbers shown per port.
+ The newest number (last 500msec) is on the right. Oldest on the left. This can help identifying spikes of high latency clearing after some time. Maximum latency is the total maximum over the entire test duration. To best understand this,
+ run TRex with latency option (-l) and watch the results with this section in mind.
+
+*Platform_factor*:: There are cases in which we duplicate the traffic using splitter/switch and we would like all numbers displayed by TRex to be multiplied by this factor, so that TRex counters will match the DUT counters.
+
+WARNING: If you don't see rx packets, revisit your MAC address configuration.
+
+include::trex_book_basic.asciidoc[]
+
+== Advanced features
+
+=== VLAN Trunk support
+
+anchor:trex_vlan[]
+
+The VLAN Trunk TRex feature attempts to solve the router port bandwidth limitation when the traffic profile is asymmetric. Example: Asymmetric SFR profile.
+This feature converts asymmetric traffic to symmetric, from the port perspective, using router sub-interfaces.
+This requires TRex to send the traffic on two VLANs, as described below.
+
+.YAML format
+[source,python]
+----
+ vlan : { enable : 1 , vlan0 : 100 , vlan1 : 200 }
+----
+
+
+.Example
+[source,python]
+----
+- duration : 0.1
+ vlan : { enable : 1 , vlan0 : 100 , vlan1 : 200 } <1>
+----
+<1> Enable VLAN feature, vlan0==100 , vlan1==200
+
+*Problem definition:*::
+
+Scenario: TRex with two ports and an SFR traffic profile.
+
+.Without VLAN/sub interfaces
+[source,python]
+----
+0 ( client) -> [ ] - 1 ( server)
+----
+Without VLAN support the traffic is asymmetric. 10% of the traffic is sent from port 0 (client side), 90% is from port 1 (server). Port 1 become the bottlneck (10Gb/s limit) before port 0.
+
+.With VLAN/sub interfaces
+[source,python]
+----
+port 0 ( client VLAN0) <-> | | <-> port 1 ( server-VLAN0)
+port 0 ( server VLAN1) <-> | | <-> port 1 ( client-VLAN1)
+----
+
+In this case both ports have the same amount of traffic.
+
+*Router configuation:*::
+[source,python]
+----
+ !
+ interface TenGigabitEthernet1/0/0 <1>
+ mac-address 0000.0001.0000
+ mtu 4000
+ no ip address
+ load-interval 30
+ !
+ i
+ interface TenGigabitEthernet1/0/0.100
+ encapsulation dot1Q 100 <2>
+ ip address 11.77.11.1 255.255.255.0
+ ip nbar protocol-discovery
+ ip policy route-map vlan_100_p1_to_p2 <3>
+ !
+ interface TenGigabitEthernet1/0/0.200
+ encapsulation dot1Q 200 <4>
+ ip address 11.88.11.1 255.255.255.0
+ ip nbar protocol-discovery
+ ip policy route-map vlan_200_p1_to_p2 <5>
+ !
+ interface TenGigabitEthernet1/1/0
+ mac-address 0000.0001.0000
+ mtu 4000
+ no ip address
+ load-interval 30
+ !
+ interface TenGigabitEthernet1/1/0.100
+ encapsulation dot1Q 100
+ ip address 22.77.11.1 255.255.255.0
+ ip nbar protocol-discovery
+ ip policy route-map vlan_100_p2_to_p1
+ !
+ interface TenGigabitEthernet1/1/0.200
+ encapsulation dot1Q 200
+ ip address 22.88.11.1 255.255.255.0
+ ip nbar protocol-discovery
+ ip policy route-map vlan_200_p2_to_p1
+ !
+
+ arp 11.77.11.12 0000.0001.0000 ARPA <6>
+ arp 22.77.11.12 0000.0001.0000 ARPA
+
+ route-map vlan_100_p1_to_p2 permit 10 <7>
+ set ip next-hop 22.77.11.12
+ !
+ route-map vlan_100_p2_to_p1 permit 10
+ set ip next-hop 11.77.11.12
+ !
+
+ route-map vlan_200_p1_to_p2 permit 10
+ set ip next-hop 22.88.11.12
+ !
+ route-map vlan_200_p2_to_p1 permit 10
+ set ip next-hop 11.88.11.12
+ !
+----
+<1> Disable the IP on the main port it is important.
+// above, clarify what's important
+<2> Enable VLAN1
+<3> PBR configuration
+<4> Enable VLAN2
+<5> PBR configuration
+<6> TRex destination port MAC address
+<7> PBR configuration rules
+
+=== Static source MAC address setting
+
+With this feature, TRex replaces the source MAC address with the client IP address.
+
+ Note: This feature was requested by the Cisco ISG group.
+
+
+*YAML:*::
+[source,python]
+----
+ mac_override_by_ip : true
+----
+
+.Example
+[source,python]
+----
+- duration : 0.1
+ ..
+ mac_override_by_ip : true <1>
+----
+<1> In this case, the client side MAC address looks like this:
+SRC_MAC = IPV4(IP) + 00:00
+
+=== IPv6 support
+
+Support for IPv6 includes:
+
+1. Support for pcap files containing IPv6 packets
+2. Ability to generate IPv6 traffic from pcap files containing IPv4 packets
+The following command line option enables this feature: `--ipv6`
+The keywords (`src_ipv6` and `dst_ipv6`) specify the most significant 96 bits of the IPv6 address - for example:
+
+[source,python]
+----
+ src_ipv6 : [0xFE80,0x0232,0x1002,0x0051,0x0000,0x0000]
+ dst_ipv6 : [0x2001,0x0DB8,0x0003,0x0004,0x0000,0x0000]
+----
+
+The IPv6 address is formed by placing what would typically be the IPv4
+address into the least significant 32 bits and copying the value provided
+in the src_ipv6/dst_ipv6 keywords into the most signficant 96 bits.
+If src_ipv6 and dst_ipv6 are not specified, the default
+is to form IPv4-compatible addresses (most signifcant 96 bits are zero).
+
+There is support for all plugins.
+
+*Example:*::
+[source,bash]
+----
+$sudo ./t-rex-64 -f cap2l/sfr_delay_10_1g.yaml -c 4 -p -l 100 -d 100000 -m 30 --ipv6
+----
+
+*Limitations:*::
+
+* TRex cannot generate both IPv4 and IPv6 traffic.
+* The `--ipv6` switch must be specified even when using pcap file containing only IPv6 packets.
+
+
+*Router configuration:*::
+
+[source,python]
+----
+interface TenGigabitEthernet1/0/0
+ mac-address 0000.0001.0000
+ mtu 4000
+ ip address 11.11.11.11 255.255.255.0
+ ip policy route-map p1_to_p2
+ load-interval 30
+ ipv6 enable ==> IPv6
+ ipv6 address 2001:DB8:1111:2222::1/64 <1>
+ ipv6 policy route-map ipv6_p1_to_p2 <2>
+!
+
+
+ipv6 unicast-routing <3>
+
+ipv6 neighbor 3001::2 TenGigabitEthernet0/1/0 0000.0002.0002 <4>
+ipv6 neighbor 2001::2 TenGigabitEthernet0/0/0 0000.0003.0002
+
+route-map ipv6_p1_to_p2 permit 10 <5>
+ set ipv6 next-hop 2001::2
+!
+route-map ipv6_p2_to_p1 permit 10
+ set ipv6 next-hop 3001::2
+!
+
+
+asr1k(config)#ipv6 route 4000::/64 2001::2
+asr1k(config)#ipv6 route 5000::/64 3001::2
+----
+<1> Enable IPv6
+<2> Add pbr
+<3> Enable IPv6 routing
+<4> MAC address setting. Should be TRex MAC.
+<5> PBR configuraion
+
+
+=== Client clustering configuration
+TRex supports testing complex topologies, using a feature called "client clustering".
+This feature allows more detailed clustering of clients.
+
+Let's look at the following topology:
+
+image:images/client_clustering_topology.png[title="Client Clustering"]
+
+
+We would like to configure two clusters and direct traffic to them.
+
+Using config file, you can instruct TRex to generate clients
+with specific configuration per cluster.
+
+Cluster configuration includes:
+
+* IP start range.
+* IP end range.
+* Initiator side configuration.
+* Responder side configuration.
+
+[NOTE]
+It is important to understand that this is *complimentary* to the client generator
+configured per profile - it only defines how the generator will be clustered.
+
+Let's look at an example.
+
+We have a profile defining client generator.
+
+[source,bash]
+----
+$cat cap2/dns.yaml
+- duration : 10.0
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.0.255"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 1
+ udp_aging : 1
+ cap_info :
+ - name: cap2/dns.pcap
+ cps : 1.0
+ ipg : 10000
+ rtt : 10000
+ w : 1
+----
+
+We want to create two clusters with 4 devices each.
+We also want to divide *80%* of the traffic to the upper cluster and *20%* to the lower cluster.
+
+We will create the following cluster configuration file.
+
+[source,bash]
+----
+#
+# Client configuration example file
+# The file must contain the following fields
+#
+# 'vlan' - if the entire configuration uses VLAN,
+# each client group must include vlan
+# configuration
+#
+# 'groups' - each client group must contain range of IPs
+# and initiator and responder section
+# 'count' represents the number of different MACs
+# addresses in the group.
+#
+# initiator and responder can contain 'vlan', 'src_mac', 'dst_mac'
+#
+
+# each group contains a double way VLAN configuration
+vlan: true
+
+groups:
+
+- ip_start : 16.0.0.1
+ ip_end : 16.0.0.204
+ initiator :
+ vlan : 100
+ dst_mac : "00:00:00:01:00:00"
+ responder :
+ vlan : 200
+ dst_mac : "00:00:00:01:00:00"
+
+ count : 4
+
+- ip_start : 16.0.0.205
+ ip_end : 16.0.0.255
+ initiator :
+ vlan : 101
+ dst_mac : "01:00:00:00:01:01"
+
+ responder:
+ vlan : 201
+ dst_mac : "01:00:00:00:02:01"
+
+ count : 4
+
+----
+
+The above configuration will divide the generator range of 255 clients to two clusters,
+each with 4 devices and VLAN in both directions.
+
+MACs will be allocated incrementaly, with a wrap around.
+
+e.g.
+
+* 16.0.0.1 --> 00:00:00:01:00:00
+* 16.0.0.2 --> 00:00:00:01:00:01
+* 16.0.0.3 --> 00:00:00:01:00:02
+* 16.0.0.4 --> 00:00:00:01:00:03
+* 16.0.0.5 --> 00:00:00:01:00:00
+* 16.0.0.6 --> 00:00:00:01:00:01
+
+and so on.
+
+*Usage:*
+
+[source,bash]
+----
+sudo ./t-rex-64 -f cap2/dns.yaml --client_cfg my_cfg.yaml
+----
+
+=== NAT support
+
+TRex can learn dynamic NAT/PAT translation. To enable this feature add `--learn-mode <mode>` to the command line.
+To learn the NAT translation, TRex must embed information describing the flow a packet belongs to, in the first
+packet of each flow. This can be done in two different methods, depending on the chosen <mode>.
+
+*mode 1:*::
+
+Flow info is embedded in the ACK of the first TCP SYN.
+In this mode, there is a limitation that bidirectional UDP templates (for example, DNS) are not supported.
+This mode was developed for testing NAT with firewalls (which usually do not work with mode 2).
+In this mode, TRex also learn and compensate for TCP sequence number randomization that might be done by the DUT.
+TRex can learn and compensate for seq num randomization in both directions of the connection.
+
+*mode 2:*::
+
+Flow info is added in a special IPv4 option header (8 bytes long 0x10 id). The option is added only to the first packet in the flow.
+This mode does not work with DUTs that drop packets with IP options (for example, Cisco ASA firewall).
+
+*mode 3:*::
+
+This is like mode 1, with the only change being that TRex does not learn the seq num randomization in the server->client direction.
+This mode can give much better connections per second performance than mode 1 (still, for all existing firewalls, mode 1 cps rate is more than enough).
+
+==== Examples
+
+*simple HTTP traffic*
+
+[source,bash]
+----
+$sudo ./t-rex-64 -f cap2/http_simple.yaml -c 4 -l 1000 -d 100000 -m 30 --learn-mode 1
+----
+
+*SFR traffic without bundling/ALG support*
+
+[source,bash]
+----
+$sudo ./t-rex-64 -f avl/sfr_delay_10_1g_no_bundling.yaml -c 4 -l 1000 -d 100000 -m 10 --learn-mode 2
+----
+
+*NAT terminal counters:*::
+
+[source,python]
+----
+-Global stats enabled
+ Cpu Utilization : 0.6 % 33.4 Gb/core
+ Platform_factor : 1.0
+ Total-Tx : 3.77 Gbps NAT time out : 917 <1> (0 in wait for syn+ack) <5>
+ Total-Rx : 3.77 Gbps NAT aged flow id: 0 <2>
+ Total-PPS : 505.72 Kpps Total NAT active: 163 <3> (12 waiting for syn) <6>
+ Total-CPS : 13.43 Kcps Total NAT opened: 82677 <4>
+----
+<1> Number of connections for which TRex had to send the next packet in the flow, but did not learn the NAT translation yet. Should be 0. Usually, value different than 0 is seen if the DUT drops the flow (probably because it can't handle the number of connections)
+<2> Number of flows for which when we got the translation info, flow was aged out already. Non 0 value here should be very rare. Can occur only when there is huge latency in the DUT input/output queue.
+<3> Number of flows for which we sent the first packet, but did not learn the NAT translation yet. Value seen depends on the connection per second rate and round trip time.
+<4> Total number of translations over the lifetime of the TRex instance. May be different from the total number of flows if template is uni-directional (and consequently does not need translation).
+<5> Out of the timed out flows, how many were timed out while waiting to learn the TCP seq num randomization of the server->client from the SYN+ACK packet (Seen only in --learn-mode 1)
+<6> Out of the active NAT sessions, how many are waiting to learn the client->server translation from the SYN packet (others are waiting for SYN+ACK from server) (Seen only in --learn-mode 1)
+
+*Configuration for Cisco ASR1000 Series:*::
+
+This feature was tested with the following configuration and sfr_delay_10_1g_no_bundling. yaml traffic profile.
+Client address range is 16.0.0.1 to 16.0.0.255
+
+[source,python]
+----
+interface TenGigabitEthernet1/0/0 <1>
+ mac-address 0000.0001.0000
+ mtu 4000
+ ip address 11.11.11.11 255.255.255.0
+ ip policy route-map p1_to_p2
+ ip nat inside <2>
+ load-interval 30
+!
+
+interface TenGigabitEthernet1/1/0
+ mac-address 0000.0001.0000
+ mtu 4000
+ ip address 11.11.11.11 255.255.255.0
+ ip policy route-map p1_to_p2
+ ip nat outside <3>
+ load-interval 30
+
+ip nat pool my 200.0.0.0 200.0.0.255 netmask 255.255.255.0 <4>
+
+ip nat inside source list 7 pool my overload
+access-list 7 permit 16.0.0.0 0.0.0.255 <5>
+
+ip nat inside source list 8 pool my overload <6>
+access-list 8 permit 17.0.0.0 0.0.0.255
+----
+<1> Must be connected to TRex Client port (router inside port)
+<2> NAT inside
+<3> NAT outside
+<4> Pool of outside address with overload
+<5> Match TRex YAML client range
+<6> In case of dual port TRex
+
+// verify 1 and 5 above; rephrased
+
+
+*Limitations:*::
+
+. The IPv6-IPv6 NAT feature does not exist on routers, so this feature can work only with IPv4.
+. Does not support NAT64.
+. Bundling/plugin is not fully supported. Consequently, sfr_delay_10.yaml does not work. Use sfr_delay_10_no_bundling.yaml instead.
+
+[NOTE]
+=====================================================================
+* `--learn-verify` is a TRex debug mechanism for testing the TRex learn mechanism.
+* Need to run it when DUT is configured without NAT. It will verify that the inside_ip==outside_ip and inside_port==outside_port.
+=====================================================================
+
+=== Flow order/latency verification
+
+In normal mode (without this feature enabled), received traffic is not checked by software. Hardware (Intel NIC) testing for dropped packets occurs at the end of the test. The only exception is the Latency/Jitter packets.
+This is one reason that with TRex, you *cannot* check features that terminate traffic (for example TCP Proxy).
+To enable this feature, add `--rx-check <sample>` to the command line options, where <sample> is the sample rate.
+The number of flows that will be sent to the software for verification is (1/(sample_rate). For 40Gb/sec traffic you can use a sample rate of 1/128. Watch for Rx CPU% utilization.
+
+[NOTE]
+============
+This feature changes the TTL of the sampled flows to 255 and expects to receive packets with TTL 254 or 255 (one routing hop). If you have more than one hop in your setup, use `--hops` to change it to a higher value. More than one hop is possible if there are number of routers betwean TRex client side and TRex server side.
+============
+
+This feature ensures that:
+
+* Packets get out of DUT in order (from each flow perspective).
+* There are no packet drops (no need to wait for the end of the test). Without this flag, you must wait for the end of the test in order to identify packet drops, because there is always a difference between TX and Rx, due to RTT.
+
+
+.Full example
+[source,bash]
+----
+$sudo ./t-rex-64 -f avl/sfr_delay_10_1g.yaml -c 4 -p -l 100 -d 100000 -m 30 --rx-check 128
+----
+
+[source,python]
+----
+Cpu Utilization : 0.1 % <1>
+ if| tx_ok , rx_ok , rx ,error, average , max , Jitter , max window
+ | , , check, , latency(usec),latency (usec) ,(usec) ,
+ --------------------------------------------------------------------------------
+ 0 | 1002, 1002, 2501, 0, 61 , 70, 3 | 60
+ 1 | 1002, 1002, 2012, 0, 56 , 63, 2 | 50
+ 2 | 1002, 1002, 2322, 0, 66 , 74, 5 | 68
+ 3 | 1002, 1002, 1727, 0, 58 , 68, 2 | 52
+
+ Rx Check stats enabled <2>
+ -------------------------------------------------------------------------------------------
+ rx check: avg/max/jitter latency, 94 , 744, 49 | 252 287 309 <3>
+
+ active flows: <6> 10, fif: <5> 308, drop: 0, errors: 0 <4>
+ -------------------------------------------------------------------------------------------
+----
+<1> CPU% of the Rx thread. If it is too high, *increase* the sample rate.
+<2> Rx Check section. For more detailed info, press 'r' during the test or at the end of the test.
+<3> Average latency, max latency, jitter on the template flows in microseconds. This is usually *higher* than the latency check packet because the feature works more on this packet.
+<4> Drop counters and errors counter should be zero. If not, press 'r' to see the full report or view the report at the end of the test.
+<5> fif - First in flow. Number of new flows handled by the Rx thread.
+<6> active flows - number of active flows handled by rx thread
+
+.Press R to Display Full Report
+[source,python]
+----
+ m_total_rx : 2
+ m_lookup : 2
+ m_found : 1
+ m_fif : 1
+ m_add : 1
+ m_remove : 1
+ m_active : 0
+ <1>
+ 0 0 0 0 1041 0 0 0 0 0 0 0 0 min_delta : 10 usec
+ cnt : 2
+ high_cnt : 2
+ max_d_time : 1041 usec
+ sliding_average : 1 usec <2>
+ precent : 100.0 %
+ histogram
+ -----------
+ h[1000] : 2
+ tempate_id_ 0 , errors: 0, jitter: 61 <3>
+ tempate_id_ 1 , errors: 0, jitter: 0
+ tempate_id_ 2 , errors: 0, jitter: 0
+ tempate_id_ 3 , errors: 0, jitter: 0
+ tempate_id_ 4 , errors: 0, jitter: 0
+ tempate_id_ 5 , errors: 0, jitter: 0
+ tempate_id_ 6 , errors: 0, jitter: 0
+ tempate_id_ 7 , errors: 0, jitter: 0
+ tempate_id_ 8 , errors: 0, jitter: 0
+ tempate_id_ 9 , errors: 0, jitter: 0
+ tempate_id_10 , errors: 0, jitter: 0
+ tempate_id_11 , errors: 0, jitter: 0
+ tempate_id_12 , errors: 0, jitter: 0
+ tempate_id_13 , errors: 0, jitter: 0
+ tempate_id_14 , errors: 0, jitter: 0
+ tempate_id_15 , errors: 0, jitter: 0
+ ager :
+ m_st_alloc : 1
+ m_st_free : 0
+ m_st_start : 2
+ m_st_stop : 1
+ m_st_handle : 0
+----
+<1> Errors, if any, shown here
+<2> Low pass filter on the active average of latency events
+<3> Error per template info
+
+// IGNORE: this line added to help rendition. Without this line, the "Notes and Limitations" section below does not appear.
+
+*Notes and Limitations:*::
+
+** To receive the packets TRex does the following:
+*** Changes the TTL to 0xff and expects 0xFF (loopback) or oxFE (route). (Use `--hop` to configure this value.)
+*** Adds 24 bytes of metadata as ipv4/ipv6 option header.
+// clarify "ipv4/ipv6 option header" above
+
+== Reference
+
+=== Traffic YAML (parameter of -f option)
+
+==== Global Traffic YAML section
+
+[source,python]
+----
+- duration : 10.0 <1>
+ generator : <2>
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.0.255"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 1
+ udp_aging : 1
+ mac : [0x00,0x00,0x00,0x01,0x00,0x00] <3>
+ cap_ipg : true <4>
+ cap_ipg_min : 30 <5>
+ cap_override_ipg : 200 <6>
+ vlan : { enable : 1 , vlan0 : 100 , vlan1 : 200 } <7>
+ mac_override_by_ip : true <8>
+----
+<1> Test duration (seconds). Can be overridden using the `-d` option.
+<2> See the link:trex_manual.html#_clients_servers_ip_allocation_scheme[generator] section.
+// what does note 2 mean? see somewhere else? isn't this simply the generator section?
+<3> Default source/destination MAC address. The configuration YAML can override this.
+<4> true (default) indicates that the IPG is taken from the cap file (also taking into account cap_ipg_min and cap_override_ipg if they exist). false indicates that IPG is taken from per template section.
+<5> The following two options can set the min ipg in microseconds: (if (pkt_ipg<cap_ipg_min) { pkt_ipg=cap_override_ipg} )
+<6> Value to override (microseconds), as described in note above.
+<7> Enable vlan feature. See xref:trex_vlan[trex_vlan section] for info.
+<8> Enable MAC address replacement by client IP.
+
+==== Per template section
+// clarify "per template"
+
+[source,python]
+----
+ - name: cap2/dns.pcap <1>
+ cps : 10.0 <2>
+ ipg : 10000 <3>
+ rtt : 10000 <4>
+ w : 1 <5>
+ server_addr : "48.0.0.7" <6>
+ one_app_server : true <7>
+
+----
+<1> The name of the template pcap file. Can be relative path from the t-rex-64 image directory, or an absolute path. The pcap file should include only one flow. (Exception: in case of plug-ins).
+<2> Connection per second. This is the value that will be used if specifying -m 1 from command line (giving -m x will multiply this
+<3> If the global section of the YAML file includes `cap_ipg : false`, this line sets the inter-packet gap in microseconds.
+<4> Should be set to the same value as ipg (microseconds).
+<5> Default value: w=1. This indicates to the IP generator how to generate the flows. If w=2, two flows from the same template will be generated in a burst (more for HTTP that has burst of flows).
+<6> If `one_app_server` is set to true, then all templates will use the same server.
+<7> If the same server address is required, set this value to true.
+
+
+
+=== Configuration YAML (parameter of --cfg option)
+
+anchor:trex_config[]
+
+The configuration file, in YAML format, configures TRex behavior, including:
+
+- IP address or MAC address for each port (source and destination).
+- Masked interfaces, to ensure that TRex does not try to use the management ports as traffic ports.
+- Changing the zmq/telnet TCP port.
+
+You specify which config file to use by adding --cfg <file name> to the command line arguments. +
+If no --cfg given, the default `/etc/trex_cfg.yaml` is used. +
+Configuration file examples can be found in the `$TREX_ROOT/scripts/cfg` folder.
+
+==== Basic Configurations
+
+[source,python]
+----
+ - port_limit : 2 #mandatory <1>
+ version : 2 #mandatory <2>
+ interfaces : ["03:00.0", "03:00.1"] #mandatory <3>
+ #enable_zmq_pub : true #optional <4>
+ #zmq_pub_port : 4500 #optional <5>
+ #prefix : setup1 #optional <6>
+ #limit_memory : 1024 #optional <7>
+ c : 4 #optional <8>
+ port_bandwidth_gb : 10 #optional <9>
+ port_info : # set eh mac addr mandatory
+ - default_gw : 1.1.1.1 # port 0 <10>
+ dest_mac : '00:00:00:01:00:00' # Either default_gw or dest_mac is mandatory <10>
+ src_mac : '00:00:00:02:00:00' # optional <11>
+ ip : 2.2.2.2 # optional <12>
+ vlan : 15 # optional <13>
+ - dest_mac : '00:00:00:03:00:00' # port 1
+ src_mac : '00:00:00:04:00:00'
+ - dest_mac : '00:00:00:05:00:00' # port 2
+ src_mac : '00:00:00:06:00:00'
+ - dest_mac : [0x0,0x0,0x0,0x7,0x0,0x01] # port 3 <14>
+ src_mac : [0x0,0x0,0x0,0x8,0x0,0x02] # <14>
+----
+<1> Number of ports. Should be equal to the number of interfaces listed in 3. - mandatory
+<2> Must be set to 2. - mandatory
+<3> List of interfaces to use. Run `sudo ./dpdk_setup_ports.py --show` to see the list you can choose from. - mandatory
+<4> Enable the ZMQ publisher for stats data, default is true.
+<5> ZMQ port number. Default value is good. If running two TRex instances on the same machine, each should be given distinct number. Otherwise, can remove this line.
+<6> If running two TRex instances on the same machine, each should be given distinct name. Otherwise, can remove this line. ( Passed to DPDK as --file-prefix arg)
+<7> Limit the amount of packet memory used. (Passed to dpdk as -m arg)
+<8> Number of threads (cores) TRex will use per interface pair ( Can be overridden by -c command line option )
+<9> The bandwidth of each interface in Gbs. In this example we have 10Gbs interfaces. For VM, put 1. Used to tune the amount of memory allocated by TRex.
+<10> TRex need to know the destination MAC address to use on each port. You can specify this in one of two ways: +
+Specify dest_mac directly. +
+Specify default_gw (since version 2.10). In this case (only if no dest_mac given), TRex will issue ARP request to this IP, and will use
+the result as dest MAC. If no dest_mac given, and no ARP response received, TRex will exit.
+
+<11> Source MAC to use when sending packets from this interface. If not given (since version 2.10), MAC address of the port will be used.
+<12> If given (since version 2.10), TRex will issue gratitues ARP for the ip + src MAC pair on appropriate port. In stateful mode,
+gratitues ARP for each ip will be sent every 120 seconds (Can be changed using --arp-refresh-period argument).
+<13> If given, gratitues ARP and ARP request will be sent using the given VLAN tag.
+<14> Old MAC address format. New format is supported since version v2.09.
+
+[NOTE]
+=========================================================================================
+If you use version earlier than 2.10, or choose to omit the ``ip''
+and have mac based configuration, be aware that TRex will not send any
+gratitues ARP and will not answer ARP requests. In this case, you must configure static
+ARP entries pointing to TRex port on your DUT. For an example config, you can look
+xref:trex_config[here].
+=========================================================================================
+
+To find out which interfaces (NIC ports) can be used, perform the following:
+
+[source,bash]
+----
+ $>sudo ./dpdk_setup_ports.py --show
+
+ Network devices using DPDK-compatible driver
+ ============================================
+
+ Network devices using kernel driver
+ ===================================
+ 0000:02:00.0 '82545EM Gigabit Ethernet Controller' if=eth2 drv=e1000 unused=igb_uio *Active* #<1>
+ 0000:03:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv= unused=ixgb #<2>
+ 0000:03:00.1 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv= unused=ixgb
+ 0000:13:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv= unused=ixgb
+ 0000:13:00.1 '82599ES 10-Gigabit SFI/SFP+ Network Connection' drv= unused=ixgb
+
+ Other network devices
+ =====================
+ <none>
+----
+<1> We see that 02:00.0 is active (our management port).
+<2> All other NIC ports (03:00.0, 03:00.1, 13:00.0, 13:00.1) can be used.
+
+minimum configuration file is:
+
+[source,bash]
+----
+<none>
+- port_limit : 4
+ version : 2
+ interfaces : ["03:00.0","03:00.1","13:00.1","13:00.0"]
+----
+
+==== Memory section configuration
+
+The memory section is optional. It is used when there is a need to tune the amount of memory used by TRex packet manager.
+Default values (from the TRex source code), are usually good for most users. Unless you have some unusual needs, you can
+eliminate this section.
+
+[source,python]
+----
+ - port_limit : 2
+ version : 2
+ interfaces : ["03:00.0","03:00.1"]
+ memory : <1>
+ mbuf_64 : 16380 <2>
+ mbuf_128 : 8190
+ mbuf_256 : 8190
+ mbuf_512 : 8190
+ mbuf_1024 : 8190
+ mbuf_2048 : 4096
+ traffic_mbuf_64 : 16380 <3>
+ traffic_mbuf_128 : 8190
+ traffic_mbuf_256 : 8190
+ traffic_mbuf_512 : 8190
+ traffic_mbuf_1024 : 8190
+ traffic_mbuf_2048 : 4096
+ dp_flows : 1048576 <4>
+ global_flows : 10240 <5>
+----
+<1> Memory section header
+<2> Numbers of memory buffers allocated for packets in transit, per port pair. Numbers are specified per packet size.
+<3> Numbers of memory buffers allocated for holding the part of the packet which is remained unchanged per template.
+You should increase numbers here, only if you have very large amount of templates.
+<4> Number of TRex flow objects allocated (To get best performance they are allocated upfront, and not dynamically).
+If you expect more concurrent flows than the default (1048576), enlarge this.
+<5> Number objects TRex allocates for holding NAT ``in transit'' connections. In stateful mode, TRex learn NAT
+translation by looking at the address changes done by the DUT to the first packet of each flow. So, these are the
+number of flows for which TRex sent the first flow packet, but did not learn the translation yet. Again, default
+here (10240) should be good. Increase only if you use NAT and see issues.
+
+
+==== Platform section configuration
+
+The platform section is optional. It is used to tune the performance and allocate the cores to the right NUMA
+a configuration file now has the folowing struct to support multi instance
+
+[source,python]
+----
+- version : 2
+ interfaces : ["03:00.0","03:00.1"]
+ port_limit : 2
+....
+ platform : <1>
+ master_thread_id : 0 <2>
+ latency_thread_id : 5 <3>
+ dual_if : <4>
+ - socket : 0 <5>
+ threads : [1,2,3,4] <6>
+----
+<1> Platform section header.
+<2> Hardware thread_id for control thread.
+<3> Hardware thread_id for RX thread.
+<4> ``dual_if'' section defines info for interface pairs (according to the order in ``interfaces'' list).
+each section, starting with ``- socket'' defines info for different interface pair.
+<5> The NUMA node from which memory will be allocated for use by the interface pair.
+<6> Hardware threads to be used for sending packets for the interface pair. Threads are pinned to cores, so specifying threads
+actually determines the hardware cores.
+
+*Real example:* anchor:numa-example[]
+
+We connected 2 Intel XL710 NICs close to each other on the motherboard. They shared the same NUMA:
+
+image:images/same_numa.png[title="2_NICSs_same_NUMA"]
+
+CPU utilization was very high ~100%, with c=2 and c=4 the results were same.
+
+Then, we moved the cards to different NUMAs:
+
+image:images/different_numa.png[title="2_NICSs_different_NUMAs"]
+
+*+*
+We added configuration to the /etc/trex_cfg.yaml:
+
+[source,python]
+ platform :
+ master_thread_id : 0
+ latency_thread_id : 8
+ dual_if :
+ - socket : 0
+ threads : [1, 2, 3, 4, 5, 6, 7]
+ - socket : 1
+ threads : [9, 10, 11, 12, 13, 14, 15]
+
+This gave best results: with *\~98 Gb/s* TX BW and c=7, CPU utilization became *~21%*! (40% with c=4)
+
+=== Command line options
+
+anchor:cml-line[]
+
+*--allow-coredump*::
+Allow creation of core dump.
+
+*--arp-refresh-period <num>*::
+Period in seconds between sending of gratuitous ARP for our addresses. Value of 0 means ``never send``.
+
+*-c <num>*::
+Number of hardware threads to use per interface pair. Use at least 4 for TRex 40Gbs. +
+TRex uses 2 threads for inner needs. Rest of the threads can be used. Maximum number here, can be number of free threads
+divided by number of interface pairs. +
+For virtual NICs on VM, we always use one thread per interface pair.
+
+*--cfg <file name>*::
+TRex configuration file to use. See relevant manual section for all config file options.
+
+*--checksum-offload*::
+Enable IP, TCP and UDP tx checksum offloading, using DPDK. This requires all used interfaces to support this.
+
+*--client_cfg <file>*::
+YAML file describing clients configuration. Look link:trex_manual.html#_client_clustering_configuration[here] for details.
+
+*-d <num>*::
+Duration of the test in seconds.
+
+*-e*::
+ Same as `-p`, but change the src/dst IP according to the port. Using this, you will get all the packets of the
+ same flow from the same port, and with the same src/dst IP. +
+ It will not work good with NBAR as it expects all clients ip to be sent from same direction.
+
+*-f <yaml file>*::
+Specify traffic YAML configuration file to use. Mandatory option for stateful mode.
+
+*--hops <num>*::
+ Provide number of hops in the setup (default is one hop). Relevant only if the Rx check is enabled.
+ Look link:trex_manual.html#_flow_order_latency_verification[here] for details.
+
+*--iom <mode>*::
+ I/O mode. Possible values: 0 (silent), 1 (normal), 2 (short).
+
+*--ipv6*::
+ Convert templates to IPv6 mode.
+
+*-k <num>*::
+ Run ``warm up'' traffic for num seconds before starting the test. This is needed if TRex is connected to switch running
+ spanning tree. You want the switch to see traffic from all relevant source MAC addresses before starting to send real
+ data. Traffic sent is the same used for the latency test (-l option) +
+ Current limitation (holds for TRex version 1.82): does not work properly on VM.
+
+*-l <rate>*::
+ In parallel to the test, run latency check, sending packets at rate/sec from each interface.
+
+*--learn-mode <mode>*::
+ Learn the dynamic NAT translation. Look link:trex_manual.html#_nat_support[here] for details.
+
+*--learn-verify*::
+ Used for testing the NAT learning mechanism. Do the learning as if DUT is doing NAT, but verify that packets
+ are not actually changed.
+
+*--limit-ports <port num>*::
+ Limit the number of ports used. Overrides the ``port_limit'' from config file.
+
+*--lm <hex bit mask>*::
+Mask specifying which ports will send traffic. For example, 0x1 - Only port 0 will send. 0x4 - only port 2 will send.
+This can be used to verify port connectivity. You can send packets from one port, and look at counters on the DUT.
+
+*--lo*::
+ Latency only - Send only latency packets. Do not send packets from the templates/pcap files.
+
+*-m <num>*::
+ Rate multiplier. TRex will multiply the CPS rate of each template by num.
+
+*--nc*::
+ If set, will terminate exacly at the end of the specified duration.
+ This provides faster, more accurate TRex termination.
+ By default (without this option), TRex waits for all flows to terminate gracefully. In case of a very long flow, termination might prolong.
+
+*--no-flow-control-change*::
+ Prevents TRex from changing flow control. By default (without this option), TRex disables flow control at startup for all cards, except for the Intel XL710 40G card.
+
+*--no-key*:: Daemon mode, don't get input from keyboard.
+
+*--no-watchdog*:: Disable watchdog.
+
+*-p*::
+Send all packets of the same flow from the same direction. For each flow, TRex will randomly choose between client port and
+server port, and send all the packets from this port. src/dst IPs keep their values as if packets are sent from two ports.
+Meaning, we get on the same port packets from client to server, and from server to client. +
+If you are using this with a router, you can not relay on routing rules to pass traffic to TRex, you must configure policy
+based routes to pass all traffic from one DUT port to the other. +
+
+*-pm <num>*::
+ Platform factor. If the setup includes splitter, you can multiply all statistic number displayed by TRex by this factor, so that they will match the DUT counters.
+
+*-pubd*::
+ Disable ZMQ monitor's publishers.
+
+*--rx-check <sample rate>*::
+ Enable Rx check module. Using this, each thread randomly samples 1/sample_rate of the flows and checks packet order, latency, and additional statistics for the sampled flows.
+ Note: This feature works on the RX thread.
+
+*-v <verbosity level>*::
+ Show debug info. Value of 1 shows debug info on startup. Value of 3, shows debug info during run at some cases. Might slow down operation.
+
+*--vlan*:: Relevant only for stateless mode with Intel 82599 10G NIC.
+ When configuring flow stat and latency per stream rules, assume all streams uses VLAN.
+
+*-w <num seconds>*::
+ Wait additional time between NICs initialization and sending traffic. Can be useful if DUT needs extra setup time. Default is 1 second.
+
+ifndef::backend-docbook[]
+
+
+endif::backend-docbook[]
+
+== Appendix
+
+=== Simulator
+
+The TRex simulator is a linux application (no DPDK needed) that can run on any Linux (it can also run on TRex machine itself).
+you can create output pcap file from input of traffic YAML.
+
+==== Simulator
+
+
+[source,bash]
+----
+
+$./bp-sim-64-debug -f avl/sfr_delay_10_1g.yaml -v 1
+
+ -- loading cap file avl/delay_10_http_get_0.pcap
+ -- loading cap file avl/delay_10_http_post_0.pcap
+ -- loading cap file avl/delay_10_https_0.pcap
+ -- loading cap file avl/delay_10_http_browsing_0.pcap
+ -- loading cap file avl/delay_10_exchange_0.pcap
+ -- loading cap file avl/delay_10_mail_pop_0.pcap
+ -- loading cap file avl/delay_10_mail_pop_1.pcap
+ -- loading cap file avl/delay_10_mail_pop_2.pcap
+ -- loading cap file avl/delay_10_oracle_0.pcap
+ -- loading cap file avl/delay_10_rtp_160k_full.pcap
+ -- loading cap file avl/delay_10_rtp_250k_full.pcap
+ -- loading cap file avl/delay_10_smtp_0.pcap
+ -- loading cap file avl/delay_10_smtp_1.pcap
+ -- loading cap file avl/delay_10_smtp_2.pcap
+ -- loading cap file avl/delay_10_video_call_0.pcap
+ -- loading cap file avl/delay_10_sip_video_call_full.pcap
+ -- loading cap file avl/delay_10_citrix_0.pcap
+ -- loading cap file avl/delay_10_dns_0.pcap
+ id,name , tps, cps,f-pkts,f-bytes, duration, Mb/sec, MB/sec, c-flows, PPS,total-Mbytes-duration,errors,flows #<2>
+ 00, avl/delay_10_http_get_0.pcap ,404.52,404.52, 44 , 37830 , 0.17 , 122.42 , 15.30 , 67 , 17799 , 2 , 0 , 1
+ 01, avl/delay_10_http_post_0.pcap ,404.52,404.52, 54 , 48468 , 0.21 , 156.85 , 19.61 , 85 , 21844 , 2 , 0 , 1
+ 02, avl/delay_10_https_0.pcap ,130.87,130.87, 96 , 91619 , 0.22 , 95.92 , 11.99 , 29 , 12564 , 1 , 0 , 1
+ 03, avl/delay_10_http_browsing_0.pcap ,709.89,709.89, 37 , 34425 , 0.13 , 195.50 , 24.44 , 94 , 26266 , 2 , 0 , 1
+ 04, avl/delay_10_exchange_0.pcap ,253.81,253.81, 43 , 9848 , 1.57 , 20.00 , 2.50 , 400 , 10914 , 0 , 0 , 1
+ 05, avl/delay_10_mail_pop_0.pcap ,4.76,4.76, 20 , 5603 , 0.17 , 0.21 , 0.03 , 1 , 95 , 0 , 0 , 1
+ 06, avl/delay_10_mail_pop_1.pcap ,4.76,4.76, 114 , 101517 , 0.25 , 3.86 , 0.48 , 1 , 543 , 0 , 0 , 1
+ 07, avl/delay_10_mail_pop_2.pcap ,4.76,4.76, 30 , 15630 , 0.19 , 0.60 , 0.07 , 1 , 143 , 0 , 0 , 1
+ 08, avl/delay_10_oracle_0.pcap ,79.32,79.32, 302 , 56131 , 6.86 , 35.62 , 4.45 , 544 , 23954 , 0 , 0 , 1
+ 09, avl/delay_10_rtp_160k_full.pcap ,2.78,8.33, 1354 , 1232757 , 61.24 , 27.38 , 3.42 , 170 , 3759 , 0 , 0 , 3
+ 10, avl/delay_10_rtp_250k_full.pcap ,1.98,5.95, 2069 , 1922000 , 61.38 , 30.48 , 3.81 , 122 , 4101 , 0 , 0 , 3
+ 11, avl/delay_10_smtp_0.pcap ,7.34,7.34, 22 , 5618 , 0.19 , 0.33 , 0.04 , 1 , 161 , 0 , 0 , 1
+ 12, avl/delay_10_smtp_1.pcap ,7.34,7.34, 35 , 18344 , 0.21 , 1.08 , 0.13 , 2 , 257 , 0 , 0 , 1
+ 13, avl/delay_10_smtp_2.pcap ,7.34,7.34, 110 , 96544 , 0.27 , 5.67 , 0.71 , 2 , 807 , 0 , 0 , 1
+ 14, avl/delay_10_video_call_0.pcap ,11.90,11.90, 2325 , 2532577 , 36.56 , 241.05 , 30.13 , 435 , 27662 , 3 , 0 , 1
+ 15, avl/delay_10_sip_video_call_full.pcap ,29.35,58.69, 1651 , 120315 , 24.56 , 28.25 , 3.53 , 721 , 48452 , 0 , 0 , 2
+ 16, avl/delay_10_citrix_0.pcap ,43.62,43.62, 272 , 84553 , 6.23 , 29.51 , 3.69 , 272 , 11866 , 0 , 0 , 1
+ 17, avl/delay_10_dns_0.pcap ,1975.02,1975.02, 2 , 162 , 0.01 , 2.56 , 0.32 , 22 , 3950 , 0 , 0 , 1
+
+ 00, sum ,4083.86,93928.84, 8580 , 6413941 , 0.00 , 997.28 , 124.66 , 2966 , 215136 , 12 , 0 , 23
+ Memory usage
+ size_64 : 1687
+ size_128 : 222
+ size_256 : 798
+ size_512 : 1028
+ size_1024 : 86
+ size_2048 : 4086
+ Total : 8.89 Mbytes 159% util #<1>
+
+----
+<1> the memory usage of the templates
+<2> CSV for all the templates
+
+
+=== firmware update to XL710/X710
+anchor:xl710-firmware[]
+
+To upgrade the firmware follow this
+
+==== Download the driver
+
+*Download driver i40e from link:https://downloadcenter.intel.com/download/24411/Network-Adapter-Driver-for-PCI-E-40-Gigabit-Network-Connections-under-Linux-[here]
+*Build the kernel module
+
+[source,bash]
+----
+$tar -xvzf i40e-1.3.47
+$cd i40e-1.3.47/src
+$make
+$sudo insmod i40e.ko
+----
+
+
+==== Bind the NIC to Linux
+
+In this stage we bind the NIC to Linux (take it from DPDK)
+
+[source,bash]
+----
+$sudo ./dpdk_nic_bind.py --status # show the ports
+
+Network devices using DPDK-compatible driver
+============================================
+0000:02:00.0 'Device 1583' drv=igb_uio unused= #<1>
+0000:02:00.1 'Device 1583' drv=igb_uio unused= #<2>
+0000:87:00.0 'Device 1583' drv=igb_uio unused=
+0000:87:00.1 'Device 1583' drv=igb_uio unused=
+
+$sudo dpdk_nic_bind.py -u 02:00.0 02:00.1 #<3>
+
+$sudo dpdk_nic_bind.py -b i40e 02:00.0 02:00.1 #<4>
+
+$ethtool -i p1p2 #<5>
+
+driver: i40e
+version: 1.3.47
+firmware-version: 4.24 0x800013fc 0.0.0 #<6>
+bus-info: 0000:02:00.1
+supports-statistics: yes
+supports-test: yes
+supports-eeprom-access: yes
+supports-register-dump: yes
+supports-priv-flags: yes
+
+
+$ethtool -S p1p2
+$lspci -s 02:00.0 -vvv #<7>
+
+
+----
+<1> XL710 ports that need to unbind from DPDK
+<2> XL710 ports that need to unbind from DPDK
+<3> Unbind from DPDK using this command
+<4> Bind to linux to i40e driver
+<5> Show firmware version throw linux driver
+<6> Firmare version
+<7> More info
+
+
+==== Upgrade
+
+Download NVMUpdatePackage.zip from Intel site link:http://downloadcenter.intel.com/download/24769/NVM-Update-Utility-for-Intel-Ethernet-Converged-Network-Adapter-XL710-X710-Series[here]
+It includes the utility `nvmupdate64e`
+
+Run this:
+
+[source,bash]
+----
+$sudo ./nvmupdate64e
+----
+
+You might need a power cycle and to run this command a few times to get the latest firmware
+
+==== QSFP+ support for XL710
+
+see link:https://www.google.co.il/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjJhPSH3b3LAhUp7nIKHSkACUYQFggaMAA&url=http%3A%2F%2Fwww.intel.co.id%2Fcontent%2Fdam%2Fwww%2Fpublic%2Fus%2Fen%2Fdocuments%2Frelease-notes%2Fxl710-ethernet-controller-feature-matrix.pdf&usg=AFQjCNFhwozfz-XuKGMOy9_MJDbetw15Og&sig2=ce7YU9F9Et6xf6KvqSFBxg&bvm=bv.116636494,d.bGs[QSFP+ support] for QSFP+ support and Firmware requirement for XL710
+
+
+=== TRex with ASA 5585
+
+When running TRex aginst ASA 5585, you have to notice following things:
+
+* ASA can't forward ipv4 options, so there is a need to use --learn-mode 1 (or 3) in case of NAT. In this mode, bidirectional UDP flows are not supported.
+--learn-mode 1 support TCP sequence number randomization in both sides of the connection (client to server and server client). For this to work, TRex must learn
+the translation of packets from both sides, so this mode reduce the amount of connections per second TRex can generate (The number is still high enough to test
+any existing firewall). If you need higher cps rate, you can use --learn-mode 3. This mode handles sequence number randomization on client->server side only.
+* Latency should be tested using ICMP with `--l-pkt-mode 2`
+
+==== ASA 5585 sample configuration
+
+[source,bash]
+----
+ciscoasa# show running-config
+: Saved
+
+:
+: Serial Number: JAD194801KX
+: Hardware: ASA5585-SSP-10, 6144 MB RAM, CPU Xeon 5500 series 2000 MHz, 1 CPU (4 cores)
+:
+ASA Version 9.5(2)
+!
+hostname ciscoasa
+enable password 8Ry2YjIyt7RRXU24 encrypted
+passwd 2KFQnbNIdI.2KYOU encrypted
+names
+!
+interface Management0/0
+ management-only
+ nameif management
+ security-level 100
+ ip address 10.56.216.106 255.255.255.0
+!
+interface TenGigabitEthernet0/8
+ nameif inside
+ security-level 100
+ ip address 15.0.0.1 255.255.255.0
+!
+interface TenGigabitEthernet0/9
+ nameif outside
+ security-level 0
+ ip address 40.0.0.1 255.255.255.0
+!
+boot system disk0:/asa952-smp-k8.bin
+ftp mode passive
+pager lines 24
+logging asdm informational
+mtu management 1500
+mtu inside 9000
+mtu outside 9000
+no failover
+no monitor-interface service-module
+icmp unreachable rate-limit 1 burst-size 1
+no asdm history enable
+arp outside 40.0.0.2 90e2.baae.87d1
+arp inside 15.0.0.2 90e2.baae.87d0
+arp timeout 14400
+no arp permit-nonconnected
+route management 0.0.0.0 0.0.0.0 10.56.216.1 1
+route inside 16.0.0.0 255.0.0.0 15.0.0.2 1
+route outside 48.0.0.0 255.0.0.0 40.0.0.2 1
+timeout xlate 3:00:00
+timeout pat-xlate 0:00:30
+timeout conn 1:00:00 half-closed 0:10:00 udp 0:02:00 sctp 0:02:00 icmp 0:00:02
+timeout sunrpc 0:10:00 h323 0:05:00 h225 1:00:00 mgcp 0:05:00 mgcp-pat 0:05:00
+timeout sip 0:30:00 sip_media 0:02:00 sip-invite 0:03:00 sip-disconnect 0:02:00
+timeout sip-provisional-media 0:02:00 uauth 0:05:00 absolute
+timeout tcp-proxy-reassembly 0:01:00
+timeout floating-conn 0:00:00
+user-identity default-domain LOCAL
+http server enable
+http 192.168.1.0 255.255.255.0 management
+no snmp-server location
+no snmp-server contact
+crypto ipsec security-association pmtu-aging infinite
+crypto ca trustpool policy
+telnet 0.0.0.0 0.0.0.0 management
+telnet timeout 5
+ssh stricthostkeycheck
+ssh timeout 5
+ssh key-exchange group dh-group1-sha1
+console timeout 0
+!
+tls-proxy maximum-session 1000
+!
+threat-detection basic-threat
+threat-detection statistics access-list
+no threat-detection statistics tcp-intercept
+dynamic-access-policy-record DfltAccessPolicy
+!
+class-map icmp-class
+ match default-inspection-traffic
+class-map inspection_default
+ match default-inspection-traffic
+!
+!
+policy-map type inspect dns preset_dns_map
+ parameters
+ message-length maximum client auto
+ message-length maximum 512
+policy-map icmp_policy
+ class icmp-class
+ inspect icmp
+policy-map global_policy
+ class inspection_default
+ inspect dns preset_dns_map
+ inspect ftp
+ inspect h323 h225
+ inspect h323 ras
+ inspect rsh
+ inspect rtsp
+ inspect esmtp
+ inspect sqlnet
+ inspect skinny
+ inspect sunrpc
+ inspect xdmcp
+ inspect sip
+ inspect netbios
+ inspect tftp
+ inspect ip-options
+!
+service-policy global_policy global
+service-policy icmp_policy interface outside
+prompt hostname context
+!
+jumbo-frame reservation
+!
+no call-home reporting anonymous
+: end
+ciscoasa#
+----
+
+==== TRex commands example
+
+Using these commands the configuration is:
+
+1. NAT learn mode (TCP-ACK)
+2. Delay of 1 second at start up (-k 1). It was added because ASA drops the first packets.
+3. Latency is configured to ICMP reply mode (--l-pkt-mode 2).
+
+
+*Simple HTTP:*::
+[source,bash]
+----
+$sudo ./t-rex-64 -f cap2/http_simple.yaml -d 1000 -l 1000 --l-pkt-mode 2 -m 1000 --learn-mode 1 -k 1
+----
+
+This is more realistic traffic for enterprise (we removed from SFR file the bidirectional UDP traffic templates, which (as described above), are not supported in this mode).
+
+*Enterprise profile:*::
+[source,bash]
+----
+$sudo ./t-rex-64 -f avl/sfr_delay_10_1g_asa_nat.yaml -d 1000 -l 1000 --l-pkt-mode 2 -m 4 --learn-mode 1 -k 1
+----
+
+The TRex output
+
+[source,bash]
+----
+-Per port stats table
+ ports | 0 | 1
+ -----------------------------------------------------------------------------------------
+ opackets | 106347896 | 118369678
+ obytes | 33508291818 | 118433748567
+ ipackets | 118378757 | 106338782
+ ibytes | 118434305375 | 33507698915
+ ierrors | 0 | 0
+ oerrors | 0 | 0
+ Tx Bw | 656.26 Mbps | 2.27 Gbps
+
+-Global stats enabled
+ Cpu Utilization : 18.4 % 31.7 Gb/core
+ Platform_factor : 1.0
+ Total-Tx : 2.92 Gbps NAT time out : 0 #<1> (0 in wait for syn+ack) #<1>
+ Total-Rx : 2.92 Gbps NAT aged flow id: 0 #<1>
+ Total-PPS : 542.29 Kpps Total NAT active: 163 (12 waiting for syn)
+ Total-CPS : 8.30 Kcps Nat_learn_errors: 0
+
+ Expected-PPS : 539.85 Kpps
+ Expected-CPS : 8.29 Kcps
+ Expected-BPS : 2.90 Gbps
+
+ Active-flows : 7860 Clients : 255 Socket-util : 0.0489 %
+ Open-flows : 3481234 Servers : 5375 Socket : 7860 Socket/Clients : 30.8
+ drop-rate : 0.00 bps #<1>
+ current time : 425.1 sec
+ test duration : 574.9 sec
+
+-Latency stats enabled
+ Cpu Utilization : 0.3 %
+ if| tx_ok , rx_ok , rx ,error, average , max , Jitter , max window
+ | , , check, , latency(usec),latency (usec) ,(usec) ,
+ ----------------------------------------------------------------------------------------------------------------
+ 0 | 420510, 420495, 0, 1, 58 , 1555, 14 | 240 257 258 258 219 930 732 896 830 472 190 207 729
+ 1 | 420496, 420509, 0, 1, 51 , 1551, 13 | 234 253 257 258 214 926 727 893 826 468 187 204 724
+----
+<1> These counters should be zero
+
+anchor:fedora21_example[]
+
+=== Fedora 21 Server installation
+
+Download the .iso file from link above, boot with it using Hypervisor or CIMC console. +
+Troubleshooting -> install in basic graphics mode
+
+* In packages selection, choose:
+
+** C Development Tools and Libraries
+
+** Development Tools
+
+** System Tools
+
+* Set Ethernet configuration if needed
+
+* Use default hard-drive partitions, reclaim space if needed
+
+* After installation, edit file /etc/selinux/config +
+set: +
+SELINUX=disabled
+
+* Run: +
+systemctl disable firewalld
+
+* Edit file /etc/yum.repos.d/fedora-updates.repo +
+set everywhere: +
+enabled=0
+
+* Reboot
+
+=== Configure Linux host as network emulator
+
+There are lots of Linux tutorials on the web, so this will not be full tutorial, only highlighting some key points. Commands
+were checked on Ubuntu system.
+
+For this example:
+
+1. TRex Client side network is 16.0.0.x
+2. TRex Server side network is 48.0.0.x
+3. Linux Client side network eth0 is configured with IPv4 as 172.168.0.1
+4. Linux Server side network eth1 is configured with IPv4 as 10.0.0.1
+
+[source,bash]
+----
+
+ TRex-0 (16.0.0.1->48.0.0.1 ) <-->
+
+ ( 172.168.0.1/255.255.0.0)-eth0 [linux] -( 10.0.0.1/255.255.0.0)-eth1
+
+ <--> TRex-1 (16.0.0.1<-48.0.0.1)
+
+----
+
+
+==== Enable forwarding
+One time (will be discarded after reboot): +
+
+[source,bash]
+----
+echo 1 > /proc/sys/net/ipv4/ip_forward
+----
+To make this permanent, add the following line to the file /etc/sysctl.conf: +
+----
+net.ipv4.ip_forward=1
+----
+
+==== Add static routes
+Example if for the default TRex networks, 48.0.0.0 and 16.0.0.0.
+
+Routing all traffic from 48.0.0.0 to the gateway 10.0.0.100
+[source,bash]
+----
+route add -net 48.0.0.0 netmask 255.255.0.0 gw 10.0.0.100
+----
+
+Routing all traffic from 16.0.0.0 to the gateway 172.168.0.100
+[source,bash]
+----
+route add -net 16.0.0.0 netmask 255.255.0.0 gw 172.168.0.100
+----
+If you use stateless mode, and decide to add route only in one direction, remember to disable reverse path check. +
+For example, to disable on all interfaces:
+[source,bash]
+----
+for i in /proc/sys/net/ipv4/conf/*/rp_filter ; do
+ echo 0 > $i
+done
+----
+
+Alternatively, you can edit /etc/network/interfaces, and add something like this for both ports connected to TRex.
+This will take effect, only after restarting networking (rebooting the machine in an alternative also).
+----
+auto eth1
+iface eth1 inet static
+address 16.0.0.100
+netmask 255.0.0.0
+network 16.0.0.0
+broadcast 16.255.255.255
+... same for 48.0.0.0
+----
+
+==== Add static ARP entries
+[source,bash]
+----
+sudo arp -s 10.0.0.100 <Second TRex port MAC>
+sudo arp -s 172.168.0.100 <TRex side the NICs are not visible to ifconfig, run:
+----
+
+
diff --git a/doc/trex_book_basic.asciidoc b/doc/trex_book_basic.asciidoc
new file mode 100755
index 00000000..9e376366
--- /dev/null
+++ b/doc/trex_book_basic.asciidoc
@@ -0,0 +1,3306 @@
+
+== Basic usage
+
+=== DNS basic example
+
+The following is a simple example helpful for understanding how TRex works. The example uses the TRex simulator.
+This simulator can be run on any Cisco Linux including on the TRex itself.
+TRex simulates clients and servers and generates traffic based on the pcap files provided.
+
+.Clients/Servers
+image:images/trex_model.png[title=""]
+
+The following is an example YAML-format traffic configuration file (cap2/dns_test.yaml), with explanatory notes.
+
+[source,python]
+----
+$cat cap2/dns_test.yaml
+- duration : 10.0
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1" <1>
+ clients_end : "16.0.0.255"
+ servers_start : "48.0.0.1" <2>
+ servers_end : "48.0.0.255"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 1
+ udp_aging : 1
+ cap_info :
+ - name: cap2/dns.pcap <3>
+ cps : 1.0 <4>
+ ipg : 10000 <5>
+ rtt : 10000 <6>
+ w : 1
+----
+<1> Range of clients (IPv4 format).
+<2> Range of servers (IPv4 format).
+<3> pcap file, which includes the DNS cap file that will be used as a template.
+<4> Number of connections per second to generate. In the example, 1.0 means 1 connection per secod.
+<5> Inter-packet gap (microseconds). 10,000 = 10 msec.
+<6> Should be the same as ipg.
+
+.DNS template file
+image:images/dns_wireshark.png[title=""]
+
+
+The DNS template file includes:
+
+1. *One* flow
+2. Two packets
+3. First packet: from the initiator (client -> server)
+4. Second packet: response (server -> client)
+
+TRex replaces the client_ip, client_port, and server_ip. The server_port will be remain the same.
+
+
+[source,bash]
+----
+$./bp-sim-32-debug -f cap2/dns.yaml -o my.erf -v 3
+ -- loading cap file cap2/dns.pcap
+ id,name , tps, cps,f-pkts,f-bytes, duration, Mb/sec, MB/sec, #<1>
+ 00, cap2/dns.pcap ,1.00,1.00, 2 , 170 , 0.02 , 0.00 , 0.00 ,
+ 00, sum ,1.00,1.00, 2 , 170 , 0.00 , 0.00 , 0.00 ,
+
+ Generating erf file ...
+pkt_id,time,fid,pkt_info,pkt,len,type,is_init,is_last,type,thread_id,src_ip,dest_ip,src_port #<2>
+ 1 ,0.010000,1,0x9055598,1,77,0,1,0,0,0,10000001,30000001,1024
+ 2 ,0.020000,1,0x9054760,2,93,0,0,1,0,0,10000001,30000001,1024
+ 3 ,2.010000,2,0x9055598,1,77,0,1,0,0,0,10000002,30000002,1024
+ 4 ,2.020000,2,0x9054760,2,93,0,0,1,0,0,10000002,30000002,1024
+ 5 ,3.010000,3,0x9055598,1,77,0,1,0,0,0,10000003,30000003,1024
+ 6 ,3.020000,3,0x9054760,2,93,0,0,1,0,0,10000003,30000003,1024
+ 7 ,4.010000,4,0x9055598,1,77,0,1,0,0,0,10000004,30000004,1024
+ 8 ,4.020000,4,0x9054760,2,93,0,0,1,0,0,10000004,30000004,1024
+ 9 ,5.010000,5,0x9055598,1,77,0,1,0,0,0,10000005,30000005,1024
+ 10 ,5.020000,5,0x9054760,2,93,0,0,1,0,0,10000005,30000005,1024
+ 11 ,6.010000,6,0x9055598,1,77,0,1,0,0,0,10000006,30000006,1024
+ 12 ,6.020000,6,0x9054760,2,93,0,0,1,0,0,10000006,30000006,1024
+ 13 ,7.010000,7,0x9055598,1,77,0,1,0,0,0,10000007,30000007,1024
+ 14 ,7.020000,7,0x9054760,2,93,0,0,1,0,0,10000007,30000007,1024
+ 15 ,8.010000,8,0x9055598,1,77,0,1,0,0,0,10000008,30000008,1024
+ 16 ,8.020000,8,0x9054760,2,93,0,0,1,0,0,10000008,30000008,1024
+ 17 ,9.010000,9,0x9055598,1,77,0,1,0,0,0,10000009,30000009,1024
+ 18 ,9.020000,9,0x9054760,2,93,0,0,1,0,0,10000009,30000009,1024
+ 19 ,10.010000,a,0x9055598,1,77,0,1,0,0,0,1000000a,3000000a,1024
+ 20 ,10.020000,a,0x9054760,2,93,0,0,1,0,0,1000000a,3000000a,1024
+
+file stats
+=================
+ m_total_bytes : 1.66 Kbytes
+ m_total_pkt : 20.00 pkt
+ m_total_open_flows : 10.00 flows
+ m_total_pkt : 20
+ m_total_open_flows : 10
+ m_total_close_flows : 10
+ m_total_bytes : 1700
+----
+<1> Global statistics on the templates given. cps=connection per second. tps is template per second. they might be different in case of plugins where one template includes more than one flow. For example RTP flow in SFR profile (avl/delay_10_rtp_160k_full.pcap)
+<2> Generator output.
+
+
+[source,bash]
+----
+$wireshark my.erf
+----
+gives
+//TBD: Not sure what the output looks like here, with this line showing only "gives"
+
+.TRex generated output file
+//??? missing picture
+image:images/dns_trex_run.png[title="generator"]
+
+As the output file shows...
+
+- TRex generates a new flow every 1 sec.
+- Client IP values are taken from client IP pool .
+- Servers IP values are taken from server IP pool .
+- IPG (iter packet gap) values are taken from the configuration file (10 msec).
+
+
+[NOTE]
+=====================================================================
+In basic usage, TRex does not wait for an initiator packet to be received. The response packet will be triggered based only on timeout (IPG in this example).
+In advanced scenarios (for example, NAT), The first packet of the flow can process by TRex software and initiate the response packet only when a packet is received.
+Consequently, it is necessary to *process* the template pcap file offline and ensure that there is enough round-trip delay (RTT) between client and server packets.
+One approach is to record the flow with a Pagent that creats RTT (10 msec RTT in the example), recording the traffic at some distance from both the client and server (not close to either side).
+This ensures sufficient delay that packets from each side will arrive without delay in the DUT. TRex-dev will work on an offline tool that will make it even simpler.
+Another approach is to change the `yaml` `ipg` field to a high enough value (bigger than 10msec ).
+=====================================================================
+
+Converting the simulator text results in a table similar to the following:
+
+.DNS example formatted results
+[format="csv",cols="1^,2^,1^,1^,2^,1^,2^,1^", options="header"]
+|=================
+ pkt,time sec,fid,flow-pkt-id,client_ip,client_port,server_ip ,direction
+ 1 , 0.010000 , 1 , 1 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 2 , 0.020000 , 1 , 2 , 16.0.0.1 , 1024 , 48.0.0.1 , <-
+ 3 , 2.010000 , 2 , 1 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 4 , 2.020000 , 2 , 2 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 5 , 3.010000 , 3 , 1 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 6 , 3.020000 , 3 , 2 , 16.0.0.3 , 1024 , 48.0.0.3 , <-
+ 7 , 4.010000 , 4 , 1 , 16.0.0.4 , 1024 , 48.0.0.4 , ->
+ 8 , 4.020000 , 4 , 2 , 16.0.0.4 , 1024 , 48.0.0.4 , <-
+ 9 , 5.010000 , 5 , 1 , 16.0.0.5 , 1024 , 48.0.0.5 , ->
+ 10 , 5.020000 , 5 , 2 , 16.0.0.5 , 1024 , 48.0.0.5 , <-
+ 11 , 6.010000 , 6 , 1 , 16.0.0.6 , 1024 , 48.0.0.6 , ->
+ 12 , 6.020000 , 6 , 2 , 16.0.0.6 , 1024 , 48.0.0.6 , <-
+ 13 , 7.010000 , 7 , 1 , 16.0.0.7 , 1024 , 48.0.0.7 , ->
+ 14 , 7.020000 , 7 , 2 , 16.0.0.7 , 1024 , 48.0.0.7 , <-
+ 15 , 8.010000 , 8 , 1 , 16.0.0.8 , 1024 , 48.0.0.8 , ->
+ 16 , 8.020000 , 8 , 2 , 16.0.0.8 , 1024 , 48.0.0.8 , <-
+ 17 , 9.010000 , 9 , 1 , 16.0.0.9 , 1024 , 48.0.0.9 , ->
+ 18 , 9.020000 , 9 , 2 , 16.0.0.9 , 1024 , 48.0.0.9 , <-
+ 19 , 10.010000 , a , 1 , 16.0.0.10 , 1024 , 48.0.0.10 , ->
+ 20 , 10.020000 , a , 2 , 16.0.0.10 , 1024 , 48.0.0.10 , <-
+|=================
+
+where:
+fid::
+ Flow ID - different IDs for each flow.
+
+low-pkt-id::
+ Packet ID within the flow. Numbering begins with 1.
+
+client_ip::
+ Client IP address.
+
+client_port::
+ Client IP port.
+
+server_ip::
+ Server IP address.
+
+direction::
+ Direction. "->" is client-to-server; "<-" is server-to-client.
+
+
+
+The following enlarges the CPS and reduces the duration.
+
+[source,python]
+----
+$more cap2/dns_test.yaml
+- duration : 1.0 <1>
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.0.255"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 1
+ udp_aging : 1
+ mac : [0x00,0x00,0x00,0x01,0x00,0x00]
+ cap_info :
+ - name: cap2/dns.pcap
+ cps : 10.0 <2>
+ ipg : 50000 <3>
+ rtt : 50000
+ w : 1
+----
+<1> Duration is 1 second.
+<2> CPS is 10.0.
+<3> IPG is 50 msec.
+
+
+Running this produces the following output:
+
+[source,bash]
+----
+$./bp-sim-32-debug -f cap2/dns_test.yaml -o my.erf -v 3
+----
+
+.Formated results
+[format="csv",cols="1^,2^,1^,1^,1^,2^,1^,2^,1^", options="header"]
+|=================
+pkt,time sec,template,fid,flow-pkt-id,client_ip,client_port,server_ip ,desc
+ 1 , 0.010000 , 0 , 1 , 1 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 2 , 0.060000 , 0 , 1 , 2 , 16.0.0.1 , 1024 , 48.0.0.1 , <-
+ 3 , 0.210000 , 0 , 2 , 1 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 4 , 0.260000 , 0 , 2 , 2 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 5 , 0.310000 , 0 , 3 , 1 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 6 , 0.360000 , 0 , 3 , 2 , 16.0.0.3 , 1024 , 48.0.0.3 , <-
+ 7 , 0.410000 , 0 , 4 , 1 , 16.0.0.4 , 1024 , 48.0.0.4 , ->
+ 8 , 0.460000 , 0 , 4 , 2 , 16.0.0.4 , 1024 , 48.0.0.4 , <-
+ 9 , 0.510000 , 0 , 5 , 1 , 16.0.0.5 , 1024 , 48.0.0.5 , ->
+ 10 , 0.560000 , 0 , 5 , 2 , 16.0.0.5 , 1024 , 48.0.0.5 , <-
+ 11 , 0.610000 , 0 , 6 , 1 , 16.0.0.6 , 1024 , 48.0.0.6 , ->
+ 12 , 0.660000 , 0 , 6 , 2 , 16.0.0.6 , 1024 , 48.0.0.6 , <-
+ 13 , 0.710000 , 0 , 7 , 1 , 16.0.0.7 , 1024 , 48.0.0.7 , ->
+ 14 , 0.760000 , 0 , 7 , 2 , 16.0.0.7 , 1024 , 48.0.0.7 , <-
+ 15 , 0.810000 , 0 , 8 , 1 , 16.0.0.8 , 1024 , 48.0.0.8 , ->
+ 16 , 0.860000 , 0 , 8 , 2 , 16.0.0.8 , 1024 , 48.0.0.8 , <-
+ 17 , 0.910000 , 0 , 9 , 1 , 16.0.0.9 , 1024 , 48.0.0.9 , ->
+ 18 , 0.960000 , 0 , 9 , 2 , 16.0.0.9 , 1024 , 48.0.0.9 , <-
+ 19 , 1.010000 , 0 , a , 1 , 16.0.0.10 , 1024 , 48.0.0.10 , ->
+ 20 , 1.060000 , 0 , a , 2 , 16.0.0.10 , 1024 , 48.0.0.10 , <-
+|=================
+
+Use the following to display the output as a chart, with:
+x axis: time (seconds)
+y axis: flow ID
+The output indicates that there are 10 flows in 1 second, as expected, and the IPG is 50 msec +
+
+ifndef::backend-docbook[]
++++++++++++++++++++++++++++++++++
+<div id="chart1" style="font : 10px sans-serif"; ></div>
+
+<script>
+var dns_data=[
+[ 0.010000 , 1 , 0 , 1 ],
+[ 0.060000 , 1 , 0 , 2 ],
+[ 0.210000 , 2 , 0 , 1 ],
+[ 0.260000 , 2 , 0 , 2 ],
+[ 0.310000 , 3 , 0 , 1 ],
+[ 0.360000 , 3 , 0 , 2 ],
+[ 0.410000 , 4 , 0 , 1 ],
+[ 0.460000 , 4 , 0 , 2 ],
+[ 0.510000 , 5 , 0 , 1 ],
+[ 0.560000 , 5 , 0 , 2 ],
+[ 0.610000 , 6 , 0 , 1 ],
+[ 0.660000 , 6 , 0 , 2 ],
+[ 0.710000 , 7 , 0 , 1 ],
+[ 0.760000 , 7 , 0 , 2 ],
+[ 0.810000 , 8 , 0 , 1 ],
+[ 0.860000 , 8 , 0 , 2 ],
+[ 0.910000 , 9 , 0 , 1 ],
+[ 0.960000 , 9 , 0 , 2 ],
+[ 1.010000 , 10 , 0 , 1 ],
+[ 1.060000 , 10 , 0 , 2 ],
+];
+chart("#chart1",dns_data,["dns"],"time-sec","flow-id");
+</script>
++++++++++++++++++++++++++++++++++
+endif::backend-docbook[]
+
+[NOTE]
+=====================================================================
+Note the gap in the second flow generation. This is an expected schedular artifact and does not have an effect.
+=====================================================================
+
+=== DNS, take flow IPG from pcap file
+
+In the following example the IPG is taken from the IPG itself.
+
+[source,python]
+----
+- duration : 1.0
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.0.255"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 0
+ udp_aging : 0
+ mac : [0x00,0x00,0x00,0x01,0x00,0x00]
+ cap_ipg : true <1>
+ #cap_ipg_min : 30
+ #cap_override_ipg : 200
+ cap_info :
+ - name: cap2/dns.pcap
+ cps : 10.0
+ ipg : 10000
+ rtt : 10000
+ w : 1
+----
+<1> IPG is taken from pcap.
+
+
+.dns ipg from pcap file
+[format="csv",cols="1^,2^,1^,1^,1^,2^,1^,2^,1^", options="header"]
+|=================
+pkt,time sec,template,fid,flow-pkt-id,client_ip,client_port,server_ip ,desc
+ 1 , 0.010000 , 0 , 1 , 1 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 2 , 0.030944 , 0 , 1 , 2 , 16.0.0.1 , 1024 , 48.0.0.1 , <-
+ 3 , 0.210000 , 0 , 2 , 1 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 4 , 0.230944 , 0 , 2 , 2 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 5 , 0.310000 , 0 , 3 , 1 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 6 , 0.330944 , 0 , 3 , 2 , 16.0.0.3 , 1024 , 48.0.0.3 , <-
+ 7 , 0.410000 , 0 , 4 , 1 , 16.0.0.4 , 1024 , 48.0.0.4 , ->
+ 8 , 0.430944 , 0 , 4 , 2 , 16.0.0.4 , 1024 , 48.0.0.4 , <-
+ 9 , 0.510000 , 0 , 5 , 1 , 16.0.0.5 , 1024 , 48.0.0.5 , ->
+ 10 , 0.530944 , 0 , 5 , 2 , 16.0.0.5 , 1024 , 48.0.0.5 , <-
+ 11 , 0.610000 , 0 , 6 , 1 , 16.0.0.6 , 1024 , 48.0.0.6 , ->
+ 12 , 0.630944 , 0 , 6 , 2 , 16.0.0.6 , 1024 , 48.0.0.6 , <-
+ 13 , 0.710000 , 0 , 7 , 1 , 16.0.0.7 , 1024 , 48.0.0.7 , ->
+ 14 , 0.730944 , 0 , 7 , 2 , 16.0.0.7 , 1024 , 48.0.0.7 , <-
+ 15 , 0.810000 , 0 , 8 , 1 , 16.0.0.8 , 1024 , 48.0.0.8 , ->
+ 16 , 0.830944 , 0 , 8 , 2 , 16.0.0.8 , 1024 , 48.0.0.8 , <-
+ 17 , 0.910000 , 0 , 9 , 1 , 16.0.0.9 , 1024 , 48.0.0.9 , ->
+ 18 , 0.930944 , 0 , 9 , 2 , 16.0.0.9 , 1024 , 48.0.0.9 , <-
+ 19 , 1.010000 , 0 , a , 1 , 16.0.0.10 , 1024 , 48.0.0.10 , ->
+ 20 , 1.030944 , 0 , a , 2 , 16.0.0.10 , 1024 , 48.0.0.10 , <-
+|=================
+
+In this example, the IPG was taken from the pcap file, which is closer to 20 msec and not 50 msec (taken from the configuration file).
+
+[source,python]
+----
+ #cap_ipg_min : 30 <1>
+ #cap_override_ipg : 200 <2>
+----
+<1> Sets the minimum IPG (microseconds) which should be override : ( if (pkt_ipg<cap_ipg_min) { pkt_ipg = cap_override_ipg } )
+<2> Value to override (microseconds).
+
+
+ifndef::backend-docbook[]
++++++++++++++++++++++++++++++++++
+<div id="chart2" style="font : 10px sans-serif"; ></div>
+
+<script>
+var chart2_data=[
+[ 0.010000 , 1 , 0 , 1 ],
+[ 0.030944 , 1 , 0 , 2 ],
+[ 0.210000 , 2 , 0 , 1 ],
+[ 0.230944 , 2 , 0 , 2 ],
+[ 0.310000 , 3 , 0 , 1 ],
+[ 0.330944 , 3 , 0 , 2 ],
+[ 0.410000 , 4 , 0 , 1 ],
+[ 0.430944 , 4 , 0 , 2 ],
+[ 0.510000 , 5 , 0 , 1 ],
+[ 0.530944 , 5 , 0 , 2 ],
+[ 0.610000 , 6 , 0 , 1 ],
+[ 0.630944 , 6 , 0 , 2 ],
+[ 0.710000 , 7 , 0 , 1 ],
+[ 0.730944 , 7 , 0 , 2 ],
+[ 0.810000 , 8 , 0 , 1 ],
+[ 0.830944 , 8 , 0 , 2 ],
+[ 0.910000 , 9 , 0 , 1 ],
+[ 0.930944 , 9 , 0 , 2 ],
+[ 1.010000 , 10 , 0 , 1 ],
+[ 1.030944 , 10 , 0 , 2 ],
+];
+chart("#chart2",chart2_data,["dns"],"time-sec","flow-id");
+</script>
++++++++++++++++++++++++++++++++++
+endif::backend-docbook[]
+
+
+=== DNS, Set one server ip
+
+In this example the server IP is taken from the template.
+
+[source,python]
+----
+- duration : 10.0
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.1.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.0.255"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 1
+ udp_aging : 1
+ mac : [0x00,0x00,0x00,0x01,0x00,0x00]
+ cap_ipg : true
+ #cap_ipg_min : 30
+ #cap_override_ipg : 200
+ cap_info :
+ - name: cap2/dns.pcap
+ cps : 1.0
+ ipg : 10000
+ rtt : 10000
+ server_addr : "48.0.0.7" <1>
+ one_app_server : true <2>
+ w : 1
+----
+<1> All templates will use the same server.
+<2> Must be set to "true".
+
+
+.dns ipg from pcap file
+[format="csv",cols="1^,2^,1^,1^,2^,1^,2^,1^", options="header"]
+|=================
+pkt,time sec,fid,flow-pkt-id,client_ip,client_port,server_ip ,desc
+ 1 , 0.010000 , 1 , 1 , 16.0.0.1 , 1024 , 48.0.0.7 , ->
+ 2 , 0.030944 , 1 , 2 , 16.0.0.1 , 1024 , 48.0.0.7 , <-
+ 3 , 2.010000 , 2 , 1 , 16.0.0.2 , 1024 , 48.0.0.7 , ->
+ 4 , 2.030944 , 2 , 2 , 16.0.0.2 , 1024 , 48.0.0.7 , <-
+ 5 , 3.010000 , 3 , 1 , 16.0.0.3 , 1024 , 48.0.0.7 , ->
+ 6 , 3.030944 , 3 , 2 , 16.0.0.3 , 1024 , 48.0.0.7 , <-
+ 7 , 4.010000 , 4 , 1 , 16.0.0.4 , 1024 , 48.0.0.7 , ->
+ 8 , 4.030944 , 4 , 2 , 16.0.0.4 , 1024 , 48.0.0.7 , <-
+ 9 , 5.010000 , 5 , 1 , 16.0.0.5 , 1024 , 48.0.0.7 , ->
+ 10 , 5.030944 , 5 , 2 , 16.0.0.5 , 1024 , 48.0.0.7 , <-
+ 11 , 6.010000 , 6 , 1 , 16.0.0.6 , 1024 , 48.0.0.7 , ->
+ 12 , 6.030944 , 6 , 2 , 16.0.0.6 , 1024 , 48.0.0.7 , <-
+ 13 , 7.010000 , 7 , 1 , 16.0.0.7 , 1024 , 48.0.0.7 , ->
+ 14 , 7.030944 , 7 , 2 , 16.0.0.7 , 1024 , 48.0.0.7 , <-
+ 15 , 8.010000 , 8 , 1 , 16.0.0.8 , 1024 , 48.0.0.7 , ->
+ 16 , 8.030944 , 8 , 2 , 16.0.0.8 , 1024 , 48.0.0.7 , <-
+ 17 , 9.010000 , 9 , 1 , 16.0.0.9 , 1024 , 48.0.0.7 , ->
+ 18 , 9.030944 , 9 , 2 , 16.0.0.9 , 1024 , 48.0.0.7 , <-
+ 19 , 10.010000 , a , 1 , 16.0.0.10 , 1024 , 48.0.0.7 , ->
+ 20 , 10.030944 , a , 2 , 16.0.0.10 , 1024 , 48.0.0.7 , <-
+|=================
+
+
+=== DNS, Reduce the number of clients
+//TBD: clarify
+
+[source,python]
+----
+- duration : 10.0
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1" <1>
+ clients_end : "16.0.0.1"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.0.3"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 1
+ udp_aging : 1
+ mac : [0x00,0x00,0x00,0x01,0x00,0x00]
+ cap_ipg : true
+ #cap_ipg_min : 30
+ #cap_override_ipg : 200
+ cap_info :
+ - name: cap2/dns.pcap
+ cps : 1.0
+ ipg : 10000
+ rtt : 10000
+ w : 1
+----
+<1> Only one client.
+
+
+.dns ipg from pcap file
+[format="csv",cols="1^,2^,1^,1^,2^,1^,2^,1^", options="header"]
+|=================
+pkt,time sec,fid,flow-pkt-id,client_ip,client_port,server_ip ,desc
+ 1 , 0.010000 , 1 , 1 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 2 , 0.030944 , 1 , 2 , 16.0.0.1 , 1024 , 48.0.0.1 , <-
+ 3 , 2.010000 , 2 , 1 , 16.0.0.1 , 1025 , 48.0.0.2 , ->
+ 4 , 2.030944 , 2 , 2 , 16.0.0.1 , 1025 , 48.0.0.2 , <-
+ 5 , 3.010000 , 3 , 1 , 16.0.0.1 , 1026 , 48.0.0.3 , ->
+ 6 , 3.030944 , 3 , 2 , 16.0.0.1 , 1026 , 48.0.0.3 , <-
+ 7 , 4.010000 , 4 , 1 , 16.0.0.1 , 1027 , 48.0.0.4 , ->
+ 8 , 4.030944 , 4 , 2 , 16.0.0.1 , 1027 , 48.0.0.4 , <-
+ 9 , 5.010000 , 5 , 1 , 16.0.0.1 , 1028 , 48.0.0.5 , ->
+ 10 , 5.030944 , 5 , 2 , 16.0.0.1 , 1028 , 48.0.0.5 , <-
+ 11 , 6.010000 , 6 , 1 , 16.0.0.1 , 1029 , 48.0.0.6 , ->
+ 12 , 6.030944 , 6 , 2 , 16.0.0.1 , 1029 , 48.0.0.6 , <-
+ 13 , 7.010000 , 7 , 1 , 16.0.0.1 , 1030 , 48.0.0.7 , ->
+ 14 , 7.030944 , 7 , 2 , 16.0.0.1 , 1030 , 48.0.0.7 , <-
+ 15 , 8.010000 , 8 , 1 , 16.0.0.1 , 1031 , 48.0.0.8 , ->
+ 16 , 8.030944 , 8 , 2 , 16.0.0.1 , 1031 , 48.0.0.8 , <-
+ 17 , 9.010000 , 9 , 1 , 16.0.0.1 , 1032 , 48.0.0.9 , ->
+ 18 , 9.030944 , 9 , 2 , 16.0.0.1 , 1032 , 48.0.0.9 , <-
+ 19 , 10.010000 , a , 1 , 16.0.0.1 , 1033 , 48.0.0.10 , ->
+ 20 , 10.030944 , a , 2 , 16.0.0.1 , 1033 , 48.0.0.10 , <-
+|=================
+
+In this case there is only one client so only ports are used to distinc the flows
+you need to be sure that you have enogth free sockets when running TRex in high rates
+
+[source,python]
+----
+ Active-flows : 0 Clients : 1 <1> Socket-util : 0.0000 % <2>
+ Open-flows : 1 Servers : 254 Socket : 1 Socket/Clients : 0.0
+ drop-rate : 0.00 bps
+----
+<1> Number of clients
+<2> sockets utilization (should be lowwer than 20%, elarge the number of clients in case of an issue).
+
+=== DNS, W=1
+
+`w` is a tunable to the IP clients/servers generator. w=1 is the default behavior.
+Setting `w=2` configures a burst of two allocations from the same client. See the following example.
+
+[source,python]
+----
+- duration : 10.0
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.10"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.0.3"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 1
+ udp_aging : 1
+ mac : [0x00,0x00,0x00,0x01,0x00,0x00]
+ cap_ipg : true
+ #cap_ipg_min : 30
+ #cap_override_ipg : 200
+ cap_info :
+ - name: cap2/dns.pcap
+ cps : 1.0
+ ipg : 10000
+ rtt : 10000
+ w : 2 <1>
+----
+<1> Two clients will be allocated from the same template.
+
+
+.DNS ipg from pcap file
+[format="csv",cols="1^,2^,1^,1^,2^,1^,2^,1^", options="header"]
+|=================
+pkt,time sec,fid,flow-pkt-id,client_ip,client_port,server_ip ,desc
+ 1 , 0.010000 , 1 , 1 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 2 , 0.030944 , 1 , 2 , 16.0.0.1 , 1024 , 48.0.0.1 , <-
+ 3 , 2.010000 , 2 , 1 , 16.0.0.1 , 1025 , 48.0.0.1 , ->
+ 4 , 2.030944 , 2 , 2 , 16.0.0.1 , 1025 , 48.0.0.1 , <-
+ 5 , 3.010000 , 3 , 1 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 6 , 3.030944 , 3 , 2 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 7 , 4.010000 , 4 , 1 , 16.0.0.2 , 1025 , 48.0.0.2 , ->
+ 8 , 4.030944 , 4 , 2 , 16.0.0.2 , 1025 , 48.0.0.2 , <-
+ 9 , 5.010000 , 5 , 1 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 10 , 5.030944 , 5 , 2 , 16.0.0.3 , 1024 , 48.0.0.3 , <-
+ 11 , 6.010000 , 6 , 1 , 16.0.0.3 , 1025 , 48.0.0.3 , ->
+ 12 , 6.030944 , 6 , 2 , 16.0.0.3 , 1025 , 48.0.0.3 , <-
+ 13 , 7.010000 , 7 , 1 , 16.0.0.4 , 1024 , 48.0.0.4 , ->
+ 14 , 7.030944 , 7 , 2 , 16.0.0.4 , 1024 , 48.0.0.4 , <-
+ 15 , 8.010000 , 8 , 1 , 16.0.0.4 , 1025 , 48.0.0.4 , ->
+ 16 , 8.030944 , 8 , 2 , 16.0.0.4 , 1025 , 48.0.0.4 , <-
+ 17 , 9.010000 , 9 , 1 , 16.0.0.5 , 1024 , 48.0.0.5 , ->
+ 18 , 9.030944 , 9 , 2 , 16.0.0.5 , 1024 , 48.0.0.5 , <-
+ 19 , 10.010000 , a , 1 , 16.0.0.5 , 1025 , 48.0.0.5 , ->
+ 20 , 10.030944 , a , 2 , 16.0.0.5 , 1025 , 48.0.0.5 , <-
+|=================
+
+
+=== Mixing HTTP and DNS templates
+
+The following example combines elements of HTTP and DNS templates:
+
+
+[source,python]
+----
+- duration : 1.0
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.10"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.0.3"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 1
+ udp_aging : 1
+ mac : [0x00,0x00,0x00,0x01,0x00,0x00]
+ cap_ipg : true
+ cap_info :
+ - name: cap2/dns.pcap
+ cps : 10.0 <1>
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_http_browsing_0.pcap
+ cps : 2.0 <1>
+ ipg : 10000
+ rtt : 10000
+ w : 1
+
+----
+<1> Same CPS for both templates.
+
+This creates the following output:
+
+.DNS ipg from pcap file
+[format="csv",cols="1^,2^,1^,1^,1^,2^,1^,2^,1^", options="header"]
+|=================
+pkt,time sec,template,fid,flow-pkt-id,client_ip,client_port,server_ip ,desc
+ 1 , 0.010000 , 0 , 1 , 1 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 2 , 0.030944 , 0 , 1 , 2 , 16.0.0.1 , 1024 , 48.0.0.1 , <-
+ 3 , 0.093333 , 1 , 2 , 1 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 4 , 0.104362 , 1 , 2 , 2 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 5 , 0.115385 , 1 , 2 , 3 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 6 , 0.115394 , 1 , 2 , 4 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 7 , 0.126471 , 1 , 2 , 5 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 8 , 0.126484 , 1 , 2 , 6 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 9 , 0.137530 , 1 , 2 , 7 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 10 , 0.148609 , 1 , 2 , 8 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 11 , 0.148621 , 1 , 2 , 9 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 12 , 0.148635 , 1 , 2 , 10 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 13 , 0.159663 , 1 , 2 , 11 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 14 , 0.170750 , 1 , 2 , 12 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 15 , 0.170762 , 1 , 2 , 13 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 16 , 0.170774 , 1 , 2 , 14 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 17 , 0.176667 , 0 , 3 , 1 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 18 , 0.181805 , 1 , 2 , 15 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 19 , 0.181815 , 1 , 2 , 16 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 20 , 0.192889 , 1 , 2 , 17 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 21 , 0.192902 , 1 , 2 , 18 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+|=================
+
+Template_id::
+ 0: DNS template
+ 1: HTTP template
+
+
+ifndef::backend-docbook[]
++++++++++++++++++++++++++++++++++
+<div id="chart3" style="font : 10px sans-serif"; ></div>
+
+<script>
+var chart3_data=[
+[ 0.010000 , 1 , 0 , 1 ],
+[ 0.030944 , 1 , 0 , 2 ],
+[ 0.093333 , 2 , 1 , 1 ],
+[ 0.104362 , 2 , 1 , 2 ],
+[ 0.115385 , 2 , 1 , 3 ],
+[ 0.115394 , 2 , 1 , 4 ],
+[ 0.126471 , 2 , 1 , 5 ],
+[ 0.126484 , 2 , 1 , 6 ],
+[ 0.137530 , 2 , 1 , 7 ],
+[ 0.148609 , 2 , 1 , 8 ],
+[ 0.148621 , 2 , 1 , 9 ],
+[ 0.148635 , 2 , 1 , 10 ],
+[ 0.159663 , 2 , 1 , 11 ],
+[ 0.170750 , 2 , 1 , 12 ],
+[ 0.170762 , 2 , 1 , 13 ],
+[ 0.170774 , 2 , 1 , 14 ],
+[ 0.176667 , 3 , 0 , 1 ],
+[ 0.181805 , 2 , 1 , 15 ],
+[ 0.181815 , 2 , 1 , 16 ],
+[ 0.192889 , 2 , 1 , 17 ],
+[ 0.192902 , 2 , 1 , 18 ],
+[ 0.192914 , 2 , 1 , 19 ],
+[ 0.192927 , 2 , 1 , 20 ],
+[ 0.192939 , 2 , 1 , 21 ],
+[ 0.192951 , 2 , 1 , 22 ],
+[ 0.197611 , 3 , 0 , 2 ],
+[ 0.203944 , 2 , 1 , 23 ],
+[ 0.203950 , 2 , 1 , 24 ],
+[ 0.203956 , 2 , 1 , 25 ],
+[ 0.214620 , 2 , 1 , 26 ],
+[ 0.214633 , 2 , 1 , 27 ],
+[ 0.214645 , 2 , 1 , 28 ],
+[ 0.214658 , 2 , 1 , 29 ],
+[ 0.214671 , 2 , 1 , 30 ],
+[ 0.214682 , 2 , 1 , 31 ],
+[ 0.214695 , 2 , 1 , 32 ],
+[ 0.214707 , 2 , 1 , 33 ],
+[ 0.225264 , 2 , 1 , 34 ],
+[ 0.225269 , 2 , 1 , 35 ],
+[ 0.225274 , 2 , 1 , 36 ],
+[ 0.225279 , 2 , 1 , 37 ],
+[ 0.260000 , 4 , 0 , 1 ],
+[ 0.280944 , 4 , 0 , 2 ],
+[ 0.343333 , 5 , 0 , 1 ],
+[ 0.364277 , 5 , 0 , 2 ],
+[ 0.426667 , 6 , 0 , 1 ],
+[ 0.447611 , 6 , 0 , 2 ],
+[ 0.593333 , 7 , 0 , 1 ],
+[ 0.614277 , 7 , 0 , 2 ],
+[ 0.676667 , 8 , 1 , 1 ],
+[ 0.687696 , 8 , 1 , 2 ],
+[ 0.698719 , 8 , 1 , 3 ],
+[ 0.698728 , 8 , 1 , 4 ],
+[ 0.709805 , 8 , 1 , 5 ],
+[ 0.709818 , 8 , 1 , 6 ],
+[ 0.720864 , 8 , 1 , 7 ],
+[ 0.731943 , 8 , 1 , 8 ],
+[ 0.731955 , 8 , 1 , 9 ],
+[ 0.731968 , 8 , 1 , 10 ],
+[ 0.742997 , 8 , 1 , 11 ],
+[ 0.754084 , 8 , 1 , 12 ],
+[ 0.754096 , 8 , 1 , 13 ],
+[ 0.754108 , 8 , 1 , 14 ],
+[ 0.760000 , 9 , 0 , 1 ],
+[ 0.765139 , 8 , 1 , 15 ],
+[ 0.765148 , 8 , 1 , 16 ],
+[ 0.776223 , 8 , 1 , 17 ],
+[ 0.776236 , 8 , 1 , 18 ],
+[ 0.776248 , 8 , 1 , 19 ],
+[ 0.776261 , 8 , 1 , 20 ],
+[ 0.776273 , 8 , 1 , 21 ],
+[ 0.776285 , 8 , 1 , 22 ],
+[ 0.780944 , 9 , 0 , 2 ],
+[ 0.787278 , 8 , 1 , 23 ],
+[ 0.787284 , 8 , 1 , 24 ],
+[ 0.787289 , 8 , 1 , 25 ],
+[ 0.797954 , 8 , 1 , 26 ],
+[ 0.797967 , 8 , 1 , 27 ],
+[ 0.797979 , 8 , 1 , 28 ],
+[ 0.797992 , 8 , 1 , 29 ],
+[ 0.798004 , 8 , 1 , 30 ],
+[ 0.798016 , 8 , 1 , 31 ],
+[ 0.798029 , 8 , 1 , 32 ],
+[ 0.798041 , 8 , 1 , 33 ],
+[ 0.808598 , 8 , 1 , 34 ],
+[ 0.808603 , 8 , 1 , 35 ],
+[ 0.808608 , 8 , 1 , 36 ],
+[ 0.808613 , 8 , 1 , 37 ],
+[ 0.843333 , 10 , 0 , 1 ],
+[ 0.864277 , 10 , 0 , 2 ],
+[ 0.926667 , 11 , 0 , 1 ],
+[ 0.947611 , 11 , 0 , 2 ],
+[ 1.010000 , 12 , 0 , 1 ],
+[ 1.030944 , 12 , 0 , 2 ],
+];
+chart("#chart3",chart3_data,["dns","http"],"time-sec","flow-id");
+</script>
++++++++++++++++++++++++++++++++++
+endif::backend-docbook[]
+
+The output above illustrates two HTTP flows and ten DNS flows in 1 second, as expected.
+
+
+=== SFR traffic YAML
+
+SFR traffic includes a combination of traffic templates. This traffic mix in the example below was defined by SFR France.
+This SFR traffic profile is used as our traffic profile for our ASR1k/ISR-G2 benchmark. It is also possible to use EMIX instead of IMIX traffic.
+
+The traffic was recorded from a Spirent C100 with a Pagent that introduce 10msec delay from client and server side.
+
+[source,python]
+----
+- duration : 0.1
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.1.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.20.255"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 0
+ udp_aging : 0
+ mac : [0x0,0x0,0x0,0x1,0x0,0x00]
+ cap_ipg : true
+ cap_info :
+ - name: avl/delay_10_http_get_0.pcap
+ cps : 404.52
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_http_post_0.pcap
+ cps : 404.52
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_https_0.pcap
+ cps : 130.8745
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_http_browsing_0.pcap
+ cps : 709.89
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_exchange_0.pcap
+ cps : 253.81
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_mail_pop_0.pcap
+ cps : 4.759
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_mail_pop_1.pcap
+ cps : 4.759
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_mail_pop_2.pcap
+ cps : 4.759
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_oracle_0.pcap
+ cps : 79.3178
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_rtp_160k_full.pcap
+ cps : 2.776
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ one_app_server : false
+ plugin_id : 1 <2>
+ - name: avl/delay_10_rtp_250k_full.pcap
+ cps : 1.982
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ one_app_server : false
+ plugin_id : 1
+ - name: avl/delay_10_smtp_0.pcap
+ cps : 7.3369
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_smtp_1.pcap
+ cps : 7.3369
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_smtp_2.pcap
+ cps : 7.3369
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_video_call_0.pcap
+ cps : 11.8976
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ one_app_server : false
+ - name: avl/delay_10_sip_video_call_full.pcap
+ cps : 29.347
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ plugin_id : 2 <1>
+ one_app_server : false
+ - name: avl/delay_10_citrix_0.pcap
+ cps : 43.6248
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_dns_0.pcap
+ cps : 1975.015
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ wlength : 1
+----
+<1> Plugin for SIP protocol, used to replace the IP/port in the control flow base on the data-flow.
+//TBD: I'm placing your note into a TBD - (what are plugins should have a seperate chapter)
+<2> Plugin for RTSP protocol used to replace the IP/port in the control flow base on the data-flow.
+
+
+
+ifndef::backend-docbook[]
++++++++++++++++++++++++++++++++++
+<div id="chart4" style="font : 10px sans-serif"; ></div>
+
+<script>
+
+var sfr_data=[
+[ 0.010000 , 1 , 0 , 1 ],
+[ 0.010245 , 2 , 1 , 1 ],
+[ 0.010490 , 3 , 2 , 1 ],
+[ 0.010735 , 4 , 3 , 1 ],
+[ 0.010979 , 5 , 4 , 1 ],
+[ 0.011224 , 6 , 5 , 1 ],
+[ 0.011469 , 7 , 6 , 1 ],
+[ 0.011714 , 8 , 7 , 1 ],
+[ 0.011959 , 9 , 8 , 1 ],
+[ 0.012204 , 10 , 9 , 1 ],
+[ 0.012449 , 11 , 10 , 1 ],
+[ 0.012694 , 12 , 11 , 1 ],
+[ 0.012938 , 13 , 12 , 1 ],
+[ 0.013183 , 14 , 13 , 1 ],
+[ 0.013428 , 15 , 14 , 1 ],
+[ 0.013673 , 16 , 15 , 1 ],
+[ 0.013918 , 17 , 16 , 1 ],
+[ 0.014163 , 18 , 17 , 1 ],
+[ 0.014408 , 19 , 0 , 1 ],
+[ 0.014652 , 20 , 1 , 1 ],
+[ 0.014897 , 21 , 3 , 1 ],
+[ 0.015142 , 22 , 4 , 1 ],
+[ 0.015387 , 23 , 17 , 1 ],
+[ 0.015632 , 24 , 0 , 1 ],
+[ 0.015877 , 25 , 1 , 1 ],
+[ 0.016122 , 26 , 3 , 1 ],
+[ 0.016367 , 27 , 17 , 1 ],
+[ 0.016611 , 28 , 3 , 1 ],
+[ 0.016856 , 29 , 17 , 1 ],
+[ 0.017101 , 30 , 3 , 1 ],
+[ 0.017346 , 31 , 17 , 1 ],
+[ 0.017591 , 32 , 0 , 1 ],
+[ 0.017836 , 33 , 1 , 1 ],
+[ 0.018081 , 34 , 3 , 1 ],
+[ 0.018325 , 35 , 17 , 1 ],
+[ 0.018456 , 15 , 14 , 2 ],
+[ 0.018570 , 36 , 2 , 1 ],
+[ 0.018815 , 37 , 17 , 1 ],
+[ 0.019060 , 38 , 4 , 1 ],
+[ 0.019305 , 39 , 17 , 1 ],
+[ 0.019550 , 40 , 3 , 1 ],
+[ 0.019795 , 41 , 17 , 1 ],
+[ 0.021137 , 1 , 0 , 2 ],
+[ 0.021294 , 2 , 1 , 2 ],
+[ 0.021534 , 3 , 2 , 2 ],
+[ 0.021764 , 4 , 3 , 2 ],
+[ 0.022007 , 5 , 4 , 2 ],
+[ 0.022251 , 6 , 5 , 2 ],
+[ 0.022505 , 7 , 6 , 2 ],
+[ 0.022768 , 8 , 7 , 2 ],
+[ 0.022989 , 9 , 8 , 2 ],
+[ 0.023245 , 10 , 9 , 2 ],
+[ 0.023490 , 11 , 10 , 2 ],
+[ 0.023747 , 12 , 11 , 2 ],
+[ 0.023963 , 13 , 12 , 2 ],
+[ 0.024212 , 14 , 13 , 2 ],
+[ 0.024972 , 17 , 16 , 2 ],
+[ 0.025262 , 18 , 17 , 2 ],
+[ 0.025545 , 19 , 0 , 2 ],
+[ 0.025701 , 20 , 1 , 2 ],
+[ 0.025926 , 21 , 3 , 2 ],
+[ 0.026169 , 22 , 4 , 2 ],
+[ 0.026486 , 23 , 17 , 2 ],
+[ 0.026769 , 24 , 0 , 2 ],
+[ 0.026926 , 25 , 1 , 2 ],
+[ 0.027151 , 26 , 3 , 2 ],
+[ 0.027465 , 27 , 17 , 2 ],
+[ 0.027640 , 28 , 3 , 2 ],
+[ 0.027955 , 29 , 17 , 2 ],
+[ 0.028130 , 30 , 3 , 2 ],
+[ 0.028445 , 31 , 17 , 2 ],
+[ 0.028728 , 32 , 0 , 2 ],
+[ 0.028885 , 33 , 1 , 2 ],
+[ 0.029110 , 34 , 3 , 2 ],
+[ 0.029424 , 35 , 17 , 2 ],
+[ 0.029614 , 36 , 2 , 2 ],
+[ 0.029914 , 37 , 17 , 2 ],
+[ 0.030087 , 38 , 4 , 2 ],
+[ 0.030404 , 39 , 17 , 2 ],
+[ 0.030579 , 40 , 3 , 2 ],
+[ 0.030894 , 41 , 17 , 2 ],
+[ 0.032188 , 1 , 0 , 3 ],
+[ 0.032197 , 1 , 0 , 4 ],
+[ 0.032341 , 2 , 1 , 3 ],
+[ 0.032367 , 2 , 1 , 4 ],
+[ 0.032379 , 2 , 1 , 5 ],
+[ 0.032576 , 3 , 2 , 3 ],
+[ 0.032583 , 3 , 2 , 4 ],
+[ 0.032787 , 4 , 3 , 3 ],
+[ 0.032796 , 4 , 3 , 4 ],
+[ 0.032931 , 16 , 15 , 2 ],
+[ 0.033031 , 5 , 4 , 3 ],
+[ 0.033052 , 5 , 4 , 4 ],
+[ 0.033065 , 5 , 4 , 5 ],
+[ 0.033272 , 6 , 5 , 3 ],
+[ 0.033460 , 15 , 14 , 3 ],
+[ 0.033527 , 7 , 6 , 3 ],
+[ 0.033802 , 8 , 7 , 3 ],
+[ 0.034029 , 9 , 8 , 3 ],
+[ 0.034280 , 10 , 9 , 3 ],
+[ 0.034288 , 10 , 9 , 4 ],
+[ 0.034525 , 11 , 10 , 3 ],
+[ 0.034533 , 11 , 10 , 4 ],
+[ 0.034797 , 12 , 11 , 3 ],
+[ 0.034989 , 13 , 12 , 3 ],
+[ 0.035271 , 14 , 13 , 3 ],
+[ 0.036008 , 17 , 16 , 3 ],
+[ 0.036442 , 16 , 15 , 3 ],
+[ 0.036596 , 19 , 0 , 3 ],
+[ 0.036605 , 19 , 0 , 4 ],
+[ 0.036749 , 20 , 1 , 3 ],
+[ 0.036775 , 20 , 1 , 4 ],
+[ 0.036787 , 20 , 1 , 5 ],
+[ 0.036949 , 21 , 3 , 3 ],
+[ 0.036958 , 21 , 3 , 4 ],
+[ 0.037193 , 22 , 4 , 3 ],
+[ 0.037215 , 22 , 4 , 4 ],
+[ 0.037227 , 22 , 4 , 5 ],
+[ 0.037820 , 24 , 0 , 3 ],
+[ 0.037829 , 24 , 0 , 4 ],
+[ 0.037973 , 25 , 1 , 3 ],
+[ 0.037999 , 25 , 1 , 4 ],
+[ 0.038011 , 25 , 1 , 5 ],
+[ 0.038174 , 26 , 3 , 3 ],
+[ 0.038183 , 26 , 3 , 4 ],
+[ 0.038663 , 28 , 3 , 3 ],
+[ 0.038672 , 28 , 3 , 4 ],
+[ 0.039153 , 30 , 3 , 3 ],
+[ 0.039162 , 30 , 3 , 4 ],
+[ 0.039779 , 32 , 0 , 3 ],
+[ 0.039788 , 32 , 0 , 4 ],
+[ 0.039932 , 33 , 1 , 3 ],
+[ 0.039958 , 33 , 1 , 4 ],
+[ 0.039970 , 33 , 1 , 5 ],
+[ 0.040133 , 34 , 3 , 3 ],
+[ 0.040142 , 34 , 3 , 4 ],
+[ 0.040656 , 36 , 2 , 3 ],
+[ 0.040663 , 36 , 2 , 4 ],
+[ 0.041111 , 38 , 4 , 3 ],
+[ 0.041133 , 38 , 4 , 4 ],
+[ 0.041145 , 38 , 4 , 5 ],
+[ 0.041602 , 40 , 3 , 3 ],
+[ 0.041611 , 40 , 3 , 4 ],
+[ 0.043401 , 2 , 1 , 6 ],
+[ 0.043434 , 1 , 0 , 5 ],
+[ 0.043447 , 1 , 0 , 6 ],
+[ 0.043815 , 3 , 2 , 5 ],
+[ 0.043873 , 4 , 3 , 5 ],
+[ 0.043886 , 4 , 3 , 6 ],
+[ 0.044082 , 6 , 5 , 4 ],
+[ 0.044570 , 7 , 6 , 4 ],
+[ 0.044831 , 8 , 7 , 4 ],
+[ 0.045090 , 5 , 4 , 6 ],
+[ 0.045449 , 10 , 9 , 5 ],
+[ 0.045694 , 11 , 10 , 5 ],
+[ 0.045839 , 12 , 11 , 4 ],
+[ 0.045998 , 9 , 8 , 4 ],
+[ 0.046032 , 13 , 12 , 4 ],
+[ 0.046300 , 14 , 13 , 4 ],
+[ 0.046705 , 16 , 15 , 4 ],
+[ 0.047031 , 17 , 16 , 4 ],
+[ 0.047809 , 20 , 1 , 6 ],
+[ 0.047842 , 19 , 0 , 5 ],
+[ 0.047854 , 19 , 0 , 6 ],
+[ 0.048035 , 21 , 3 , 5 ],
+[ 0.048048 , 21 , 3 , 6 ],
+[ 0.049033 , 25 , 1 , 6 ],
+[ 0.049066 , 24 , 0 , 5 ],
+[ 0.049079 , 24 , 0 , 6 ],
+[ 0.049253 , 22 , 4 , 6 ],
+[ 0.049260 , 26 , 3 , 5 ],
+[ 0.049273 , 26 , 3 , 6 ],
+[ 0.049749 , 28 , 3 , 5 ],
+[ 0.049763 , 28 , 3 , 6 ],
+[ 0.050239 , 30 , 3 , 5 ],
+[ 0.050252 , 30 , 3 , 6 ],
+[ 0.050992 , 33 , 1 , 6 ],
+[ 0.051025 , 32 , 0 , 5 ],
+[ 0.051038 , 32 , 0 , 6 ],
+[ 0.051219 , 34 , 3 , 5 ],
+[ 0.051232 , 34 , 3 , 6 ],
+[ 0.051895 , 36 , 2 , 5 ],
+[ 0.052688 , 40 , 3 , 5 ],
+[ 0.052701 , 40 , 3 , 6 ],
+[ 0.053171 , 38 , 4 , 6 ],
+[ 0.054470 , 2 , 1 , 7 ],
+[ 0.054487 , 2 , 1 , 8 ],
+[ 0.054500 , 2 , 1 , 9 ],
+[ 0.054521 , 1 , 0 , 7 ],
+[ 0.054932 , 4 , 3 , 7 ],
+[ 0.055104 , 6 , 5 , 5 ],
+[ 0.055245 , 3 , 2 , 6 ],
+[ 0.055432 , 8 , 7 , 5 ],
+[ 0.055610 , 7 , 6 , 5 ],
+[ 0.056678 , 10 , 9 , 6 ],
+[ 0.056889 , 12 , 11 , 5 ],
+[ 0.056923 , 11 , 10 , 6 ],
+[ 0.057032 , 9 , 8 , 5 ],
+[ 0.057064 , 13 , 12 , 5 ],
+[ 0.057126 , 5 , 4 , 7 ],
+[ 0.057323 , 14 , 13 , 5 ],
+[ 0.058054 , 17 , 16 , 5 ],
+[ 0.058877 , 20 , 1 , 7 ],
+[ 0.058895 , 20 , 1 , 8 ],
+[ 0.058907 , 20 , 1 , 9 ],
+[ 0.058928 , 19 , 0 , 7 ],
+[ 0.059094 , 21 , 3 , 7 ],
+[ 0.060102 , 25 , 1 , 7 ],
+[ 0.060119 , 25 , 1 , 8 ],
+[ 0.060132 , 25 , 1 , 9 ],
+[ 0.060153 , 24 , 0 , 7 ],
+[ 0.060319 , 26 , 3 , 7 ],
+[ 0.060372 , 16 , 15 , 5 ],
+[ 0.060808 , 28 , 3 , 7 ],
+[ 0.061288 , 22 , 4 , 7 ],
+[ 0.061298 , 30 , 3 , 7 ],
+[ 0.062061 , 33 , 1 , 7 ],
+[ 0.062078 , 33 , 1 , 8 ],
+[ 0.062091 , 33 , 1 , 9 ],
+[ 0.062112 , 32 , 0 , 7 ],
+[ 0.062278 , 34 , 3 , 7 ],
+[ 0.063325 , 36 , 2 , 6 ],
+[ 0.063747 , 40 , 3 , 7 ],
+[ 0.065206 , 38 , 4 , 7 ],
+[ 0.065542 , 2 , 1 , 10 ],
+[ 0.065601 , 1 , 0 , 8 ],
+[ 0.065614 , 1 , 0 , 9 ],
+[ 0.065626 , 1 , 0 , 10 ],
+[ 0.066011 , 4 , 3 , 8 ],
+[ 0.066023 , 4 , 3 , 9 ],
+[ 0.066036 , 4 , 3 , 10 ],
+[ 0.066140 , 6 , 5 , 6 ],
+[ 0.066484 , 8 , 7 , 6 ],
+[ 0.066651 , 7 , 6 , 6 ],
+[ 0.066656 , 3 , 2 , 7 ],
+[ 0.067815 , 10 , 9 , 7 ],
+[ 0.067928 , 12 , 11 , 6 ],
+[ 0.068060 , 11 , 10 , 7 ],
+[ 0.068094 , 13 , 12 , 6 ],
+[ 0.068149 , 14 , 13 , 6 ],
+[ 0.068160 , 5 , 4 , 8 ],
+[ 0.068463 , 15 , 14 , 4 ],
+[ 0.069950 , 20 , 1 , 10 ],
+[ 0.070008 , 19 , 0 , 8 ],
+[ 0.070022 , 19 , 0 , 9 ],
+[ 0.070034 , 19 , 0 , 10 ],
+[ 0.070173 , 21 , 3 , 8 ],
+[ 0.070185 , 21 , 3 , 9 ],
+[ 0.070199 , 21 , 3 , 10 ],
+[ 0.071174 , 25 , 1 , 10 ],
+[ 0.071233 , 24 , 0 , 8 ],
+[ 0.071246 , 24 , 0 , 9 ],
+[ 0.071258 , 24 , 0 , 10 ],
+[ 0.071398 , 26 , 3 , 8 ],
+[ 0.071410 , 26 , 3 , 9 ],
+[ 0.071423 , 26 , 3 , 10 ],
+[ 0.071888 , 28 , 3 , 8 ],
+[ 0.071899 , 28 , 3 , 9 ],
+[ 0.071913 , 28 , 3 , 10 ],
+[ 0.072091 , 17 , 16 , 6 ],
+[ 0.072322 , 22 , 4 , 8 ],
+[ 0.072377 , 30 , 3 , 8 ],
+[ 0.072389 , 30 , 3 , 9 ],
+[ 0.072402 , 30 , 3 , 10 ],
+[ 0.073133 , 33 , 1 , 10 ],
+[ 0.073192 , 32 , 0 , 8 ],
+[ 0.073205 , 32 , 0 , 9 ],
+[ 0.073217 , 32 , 0 , 10 ],
+[ 0.073357 , 34 , 3 , 8 ],
+[ 0.073369 , 34 , 3 , 9 ],
+[ 0.073382 , 34 , 3 , 10 ],
+[ 0.074736 , 36 , 2 , 7 ],
+[ 0.074826 , 40 , 3 , 8 ],
+[ 0.074838 , 40 , 3 , 9 ],
+[ 0.074851 , 40 , 3 , 10 ],
+[ 0.076240 , 38 , 4 , 8 ],
+[ 0.076607 , 2 , 1 , 11 ],
+[ 0.076621 , 2 , 1 , 12 ],
+[ 0.076633 , 2 , 1 , 13 ],
+[ 0.076661 , 1 , 0 , 11 ],
+[ 0.077065 , 4 , 3 , 11 ],
+[ 0.077162 , 6 , 5 , 7 ],
+[ 0.077509 , 8 , 7 , 7 ],
+[ 0.077678 , 7 , 6 , 7 ],
+[ 0.077745 , 3 , 2 , 8 ],
+[ 0.078888 , 10 , 9 , 8 ],
+[ 0.078959 , 12 , 11 , 7 ],
+[ 0.079126 , 13 , 12 , 7 ],
+[ 0.079133 , 11 , 10 , 8 ],
+[ 0.079189 , 14 , 13 , 7 ],
+[ 0.079212 , 5 , 4 , 9 ],
+[ 0.081015 , 20 , 1 , 11 ],
+[ 0.081028 , 20 , 1 , 12 ],
+[ 0.081041 , 20 , 1 , 13 ],
+[ 0.081068 , 19 , 0 , 11 ],
+[ 0.081227 , 21 , 3 , 11 ],
+[ 0.082239 , 25 , 1 , 11 ],
+[ 0.082253 , 25 , 1 , 12 ],
+[ 0.082265 , 25 , 1 , 13 ],
+[ 0.082293 , 24 , 0 , 11 ],
+[ 0.082452 , 26 , 3 , 11 ],
+[ 0.082941 , 28 , 3 , 11 ],
+[ 0.083374 , 22 , 4 , 9 ],
+[ 0.083431 , 30 , 3 , 11 ],
+[ 0.084198 , 33 , 1 , 11 ],
+[ 0.084212 , 33 , 1 , 12 ],
+[ 0.084224 , 33 , 1 , 13 ],
+[ 0.084252 , 32 , 0 , 11 ],
+[ 0.084411 , 34 , 3 , 11 ],
+[ 0.084412 , 15 , 14 , 5 ],
+[ 0.085546 , 15 , 14 , 6 ],
+[ 0.085825 , 36 , 2 , 8 ],
+[ 0.085880 , 40 , 3 , 11 ],
+[ 0.086057 , 9 , 8 , 6 ],
+[ 0.086065 , 9 , 8 , 7 ],
+[ 0.086070 , 9 , 8 , 8 ],
+[ 0.086120 , 17 , 16 , 7 ],
+[ 0.086549 , 15 , 14 , 7 ],
+[ 0.086558 , 15 , 14 , 8 ],
+[ 0.087122 , 17 , 16 , 8 ],
+[ 0.087127 , 17 , 16 , 9 ],
+[ 0.087133 , 17 , 16 , 10 ],
+[ 0.087138 , 17 , 16 , 11 ],
+[ 0.087148 , 17 , 16 , 12 ],
+[ 0.087292 , 38 , 4 , 9 ],
+[ 0.087381 , 2 , 1 , 14 ],
+[ 0.087410 , 2 , 1 , 15 ],
+[ 0.087423 , 2 , 1 , 16 ],
+[ 0.087727 , 1 , 0 , 12 ],
+[ 0.087740 , 1 , 0 , 13 ],
+[ 0.087753 , 1 , 0 , 14 ],
+[ 0.088122 , 17 , 16 , 13 ],
+[ 0.088152 , 4 , 3 , 12 ],
+[ 0.088164 , 4 , 3 , 13 ],
+[ 0.088176 , 4 , 3 , 14 ],
+[ 0.088200 , 6 , 5 , 8 ],
+[ 0.088521 , 8 , 7 , 8 ],
+[ 0.088709 , 7 , 6 , 8 ],
+[ 0.088855 , 3 , 2 , 9 ],
+[ 0.088868 , 3 , 2 , 10 ],
+[ 0.088880 , 3 , 2 , 11 ],
+[ 0.088893 , 3 , 2 , 12 ],
+[ 0.089129 , 17 , 16 , 14 ],
+[ 0.089137 , 17 , 16 , 15 ],
+[ 0.089142 , 17 , 16 , 16 ],
+[ 0.089147 , 17 , 16 , 17 ],
+[ 0.089152 , 17 , 16 , 18 ],
+[ 0.089550 , 15 , 14 , 9 ],
+[ 0.089559 , 15 , 14 , 10 ],
+[ 0.089954 , 10 , 9 , 9 ],
+[ 0.089997 , 12 , 11 , 8 ],
+[ 0.090130 , 17 , 16 , 19 ],
+[ 0.090135 , 17 , 16 , 20 ],
+[ 0.090141 , 17 , 16 , 21 ],
+[ 0.090169 , 13 , 12 , 8 ],
+[ 0.090199 , 11 , 10 , 9 ],
+[ 0.090232 , 14 , 13 , 8 ],
+[ 0.091788 , 20 , 1 , 14 ],
+[ 0.091818 , 20 , 1 , 15 ],
+[ 0.091830 , 20 , 1 , 16 ],
+[ 0.092134 , 19 , 0 , 12 ],
+[ 0.092147 , 17 , 16 , 22 ],
+[ 0.092148 , 19 , 0 , 13 ],
+[ 0.092152 , 17 , 16 , 23 ],
+[ 0.092160 , 19 , 0 , 14 ],
+[ 0.092186 , 17 , 16 , 24 ],
+[ 0.092192 , 17 , 16 , 25 ],
+[ 0.092198 , 17 , 16 , 26 ],
+[ 0.092272 , 5 , 4 , 10 ],
+[ 0.092314 , 21 , 3 , 12 ],
+[ 0.092326 , 21 , 3 , 13 ],
+[ 0.092338 , 21 , 3 , 14 ],
+[ 0.093013 , 25 , 1 , 14 ],
+[ 0.093042 , 25 , 1 , 15 ],
+[ 0.093055 , 25 , 1 , 16 ],
+[ 0.093154 , 17 , 16 , 27 ],
+[ 0.093160 , 17 , 16 , 28 ],
+[ 0.093359 , 24 , 0 , 12 ],
+[ 0.093372 , 24 , 0 , 13 ],
+[ 0.093385 , 24 , 0 , 14 ],
+[ 0.093539 , 26 , 3 , 12 ],
+[ 0.093551 , 26 , 3 , 13 ],
+[ 0.093563 , 26 , 3 , 14 ],
+[ 0.094029 , 28 , 3 , 12 ],
+[ 0.094040 , 28 , 3 , 13 ],
+[ 0.094052 , 28 , 3 , 14 ],
+[ 0.094518 , 30 , 3 , 12 ],
+[ 0.094530 , 30 , 3 , 13 ],
+[ 0.094542 , 30 , 3 , 14 ],
+[ 0.094972 , 33 , 1 , 14 ],
+[ 0.095001 , 33 , 1 , 15 ],
+[ 0.095014 , 33 , 1 , 16 ],
+[ 0.095318 , 32 , 0 , 12 ],
+[ 0.095331 , 32 , 0 , 13 ],
+[ 0.095344 , 32 , 0 , 14 ],
+[ 0.095498 , 34 , 3 , 12 ],
+[ 0.095510 , 34 , 3 , 13 ],
+[ 0.095522 , 34 , 3 , 14 ],
+[ 0.096434 , 22 , 4 , 10 ],
+[ 0.096935 , 36 , 2 , 9 ],
+[ 0.096948 , 36 , 2 , 10 ],
+[ 0.096960 , 36 , 2 , 11 ],
+[ 0.096967 , 40 , 3 , 12 ],
+[ 0.096973 , 36 , 2 , 12 ],
+[ 0.096979 , 40 , 3 , 13 ],
+[ 0.096991 , 40 , 3 , 14 ],
+[ 0.098100 , 9 , 8 , 9 ],
+[ 0.098440 , 2 , 1 , 17 ],
+[ 0.098777 , 1 , 0 , 15 ],
+[ 0.098783 , 1 , 0 , 16 ],
+[ 0.099207 , 4 , 3 , 15 ],
+[ 0.099216 , 4 , 3 , 16 ],
+[ 0.099234 , 6 , 5 , 9 ],
+[ 0.099540 , 8 , 7 , 9 ],
+[ 0.099733 , 7 , 6 , 9 ],
+[ 0.099913 , 3 , 2 , 13 ],
+[ 0.099918 , 3 , 2 , 14 ],
+[ 0.100352 , 38 , 4 , 10 ],
+[ 0.101031 , 10 , 9 , 10 ],
+[ 0.101033 , 12 , 11 , 9 ],
+[ 0.101218 , 13 , 12 , 9 ],
+[ 0.101264 , 14 , 13 , 9 ],
+[ 0.101276 , 11 , 10 , 10 ],
+[ 0.102848 , 20 , 1 , 17 ],
+[ 0.103184 , 19 , 0 , 15 ],
+[ 0.103190 , 19 , 0 , 16 ],
+[ 0.103369 , 21 , 3 , 15 ],
+[ 0.103379 , 21 , 3 , 16 ],
+[ 0.104072 , 25 , 1 , 17 ],
+[ 0.104409 , 24 , 0 , 15 ],
+[ 0.104415 , 24 , 0 , 16 ],
+[ 0.104594 , 26 , 3 , 15 ],
+[ 0.104603 , 26 , 3 , 16 ],
+[ 0.105084 , 28 , 3 , 15 ],
+[ 0.105093 , 28 , 3 , 16 ],
+[ 0.105573 , 30 , 3 , 15 ],
+[ 0.105582 , 30 , 3 , 16 ],
+[ 0.106031 , 33 , 1 , 17 ],
+[ 0.106368 , 32 , 0 , 15 ],
+[ 0.106374 , 32 , 0 , 16 ],
+[ 0.106553 , 34 , 3 , 15 ],
+[ 0.106562 , 34 , 3 , 16 ],
+[ 0.107993 , 36 , 2 , 13 ],
+[ 0.107998 , 36 , 2 , 14 ],
+[ 0.108022 , 40 , 3 , 15 ],
+[ 0.108031 , 40 , 3 , 16 ],
+[ 0.109544 , 2 , 1 , 18 ],
+[ 0.109578 , 2 , 1 , 19 ],
+[ 0.109590 , 2 , 1 , 20 ],
+[ 0.109842 , 1 , 0 , 17 ],
+[ 0.109854 , 1 , 0 , 18 ],
+[ 0.109867 , 1 , 0 , 19 ],
+[ 0.109879 , 1 , 0 , 20 ],
+[ 0.109891 , 1 , 0 , 21 ],
+[ 0.109904 , 1 , 0 , 22 ],
+[ 0.110264 , 6 , 5 , 10 ],
+[ 0.110291 , 4 , 3 , 17 ],
+[ 0.110304 , 4 , 3 , 18 ],
+[ 0.110316 , 4 , 3 , 19 ],
+[ 0.110329 , 4 , 3 , 20 ],
+[ 0.110341 , 4 , 3 , 21 ],
+[ 0.110353 , 4 , 3 , 22 ],
+[ 0.110567 , 8 , 7 , 10 ],
+[ 0.110762 , 7 , 6 , 10 ],
+[ 0.110992 , 3 , 2 , 15 ],
+[ 0.111005 , 3 , 2 , 16 ],
+[ 0.111017 , 3 , 2 , 17 ],
+[ 0.111029 , 3 , 2 , 18 ],
+[ 0.111042 , 3 , 2 , 19 ],
+[ 0.111054 , 3 , 2 , 20 ],
+[ 0.112076 , 12 , 11 , 10 ],
+[ 0.112154 , 10 , 9 , 11 ],
+[ 0.112274 , 13 , 12 , 10 ],
+[ 0.112291 , 14 , 13 , 10 ],
+[ 0.112399 , 11 , 10 , 11 ],
+[ 0.113951 , 20 , 1 , 18 ],
+[ 0.113986 , 20 , 1 , 19 ],
+[ 0.113997 , 20 , 1 , 20 ],
+[ 0.114249 , 19 , 0 , 17 ],
+[ 0.114262 , 19 , 0 , 18 ],
+[ 0.114274 , 19 , 0 , 19 ],
+[ 0.114286 , 19 , 0 , 20 ],
+[ 0.114299 , 19 , 0 , 21 ],
+[ 0.114311 , 19 , 0 , 22 ],
+[ 0.114453 , 21 , 3 , 17 ],
+[ 0.114466 , 21 , 3 , 18 ],
+[ 0.114478 , 21 , 3 , 19 ],
+[ 0.114491 , 21 , 3 , 20 ],
+[ 0.114503 , 21 , 3 , 21 ],
+[ 0.114515 , 21 , 3 , 22 ],
+[ 0.115148 , 9 , 8 , 10 ],
+[ 0.115176 , 25 , 1 , 18 ],
+[ 0.115210 , 25 , 1 , 19 ],
+[ 0.115222 , 25 , 1 , 20 ],
+[ 0.115474 , 24 , 0 , 17 ],
+[ 0.115486 , 24 , 0 , 18 ],
+[ 0.115499 , 24 , 0 , 19 ],
+[ 0.115511 , 24 , 0 , 20 ],
+[ 0.115523 , 24 , 0 , 21 ],
+[ 0.115536 , 24 , 0 , 22 ],
+[ 0.115678 , 26 , 3 , 17 ],
+[ 0.115691 , 26 , 3 , 18 ],
+[ 0.115703 , 26 , 3 , 19 ],
+[ 0.115716 , 26 , 3 , 20 ],
+[ 0.115728 , 26 , 3 , 21 ],
+[ 0.115740 , 26 , 3 , 22 ],
+[ 0.116167 , 28 , 3 , 17 ],
+[ 0.116180 , 28 , 3 , 18 ],
+[ 0.116192 , 28 , 3 , 19 ],
+[ 0.116206 , 28 , 3 , 20 ],
+[ 0.116217 , 28 , 3 , 21 ],
+[ 0.116229 , 28 , 3 , 22 ],
+[ 0.116657 , 30 , 3 , 17 ],
+[ 0.116670 , 30 , 3 , 18 ],
+[ 0.116682 , 30 , 3 , 19 ],
+[ 0.116695 , 30 , 3 , 20 ],
+[ 0.116707 , 30 , 3 , 21 ],
+[ 0.116719 , 30 , 3 , 22 ],
+[ 0.117135 , 33 , 1 , 18 ],
+[ 0.117169 , 33 , 1 , 19 ],
+[ 0.117181 , 33 , 1 , 20 ],
+[ 0.117433 , 32 , 0 , 17 ],
+[ 0.117445 , 32 , 0 , 18 ],
+[ 0.117458 , 32 , 0 , 19 ],
+[ 0.117470 , 32 , 0 , 20 ],
+[ 0.117482 , 32 , 0 , 21 ],
+[ 0.117495 , 32 , 0 , 22 ],
+[ 0.117637 , 34 , 3 , 17 ],
+[ 0.117650 , 34 , 3 , 18 ],
+[ 0.117662 , 34 , 3 , 19 ],
+[ 0.117675 , 34 , 3 , 20 ],
+[ 0.117687 , 34 , 3 , 21 ],
+[ 0.117699 , 34 , 3 , 22 ],
+[ 0.119072 , 36 , 2 , 15 ],
+[ 0.119085 , 36 , 2 , 16 ],
+[ 0.119097 , 36 , 2 , 17 ],
+[ 0.119106 , 40 , 3 , 17 ],
+[ 0.119109 , 36 , 2 , 18 ],
+[ 0.119119 , 40 , 3 , 18 ],
+[ 0.119122 , 36 , 2 , 19 ],
+[ 0.119131 , 40 , 3 , 19 ],
+[ 0.119134 , 36 , 2 , 20 ],
+[ 0.119144 , 40 , 3 , 20 ],
+[ 0.119156 , 40 , 3 , 21 ],
+[ 0.119168 , 40 , 3 , 22 ],
+[ 0.120605 , 2 , 1 , 21 ],
+[ 0.120900 , 1 , 0 , 23 ],
+[ 0.120910 , 1 , 0 , 24 ],
+[ 0.120914 , 1 , 0 , 25 ],
+[ 0.121289 , 6 , 5 , 11 ],
+[ 0.121346 , 4 , 3 , 23 ],
+[ 0.121352 , 4 , 3 , 24 ],
+[ 0.121357 , 4 , 3 , 25 ],
+[ 0.121601 , 8 , 7 , 11 ],
+[ 0.121787 , 7 , 6 , 11 ],
+[ 0.122057 , 3 , 2 , 21 ],
+[ 0.122062 , 3 , 2 , 22 ],
+[ 0.122066 , 3 , 2 , 23 ],
+[ 0.123109 , 12 , 11 , 11 ],
+[ 0.123312 , 14 , 13 , 11 ],
+[ 0.123322 , 13 , 12 , 11 ],
+[ 0.125013 , 20 , 1 , 21 ],
+[ 0.125308 , 19 , 0 , 23 ],
+[ 0.125318 , 19 , 0 , 24 ],
+[ 0.125322 , 19 , 0 , 25 ],
+[ 0.125508 , 21 , 3 , 23 ],
+[ 0.125514 , 21 , 3 , 24 ],
+[ 0.125519 , 21 , 3 , 25 ],
+[ 0.125629 , 15 , 14 , 11 ],
+[ 0.126237 , 25 , 1 , 21 ],
+[ 0.126532 , 24 , 0 , 23 ],
+[ 0.126542 , 24 , 0 , 24 ],
+[ 0.126546 , 24 , 0 , 25 ],
+[ 0.126724 , 9 , 8 , 11 ],
+[ 0.126733 , 26 , 3 , 23 ],
+[ 0.126739 , 26 , 3 , 24 ],
+[ 0.126744 , 26 , 3 , 25 ],
+[ 0.127222 , 28 , 3 , 23 ],
+[ 0.127229 , 28 , 3 , 24 ],
+[ 0.127234 , 28 , 3 , 25 ],
+[ 0.127712 , 30 , 3 , 23 ],
+[ 0.127718 , 30 , 3 , 24 ],
+[ 0.127723 , 30 , 3 , 25 ],
+[ 0.128196 , 33 , 1 , 21 ],
+[ 0.128491 , 32 , 0 , 23 ],
+[ 0.128501 , 32 , 0 , 24 ],
+[ 0.128505 , 32 , 0 , 25 ],
+[ 0.128692 , 34 , 3 , 23 ],
+[ 0.128698 , 34 , 3 , 24 ],
+[ 0.128703 , 34 , 3 , 25 ],
+[ 0.130137 , 36 , 2 , 21 ],
+[ 0.130142 , 36 , 2 , 22 ],
+[ 0.130146 , 36 , 2 , 23 ],
+[ 0.130161 , 40 , 3 , 23 ],
+[ 0.130167 , 40 , 3 , 24 ],
+[ 0.130172 , 40 , 3 , 25 ],
+[ 0.131565 , 1 , 0 , 26 ],
+[ 0.131578 , 1 , 0 , 27 ],
+[ 0.131590 , 1 , 0 , 28 ],
+[ 0.131603 , 1 , 0 , 29 ],
+[ 0.131615 , 1 , 0 , 30 ],
+[ 0.131627 , 1 , 0 , 31 ],
+[ 0.131640 , 1 , 0 , 32 ],
+[ 0.131652 , 1 , 0 , 33 ],
+[ 0.131664 , 1 , 0 , 34 ],
+[ 0.131689 , 2 , 1 , 22 ],
+[ 0.131702 , 2 , 1 , 23 ],
+[ 0.131715 , 2 , 1 , 24 ],
+[ 0.132022 , 4 , 3 , 26 ],
+[ 0.132035 , 4 , 3 , 27 ],
+[ 0.132047 , 4 , 3 , 28 ],
+[ 0.132060 , 4 , 3 , 29 ],
+[ 0.132072 , 4 , 3 , 30 ],
+[ 0.132084 , 4 , 3 , 31 ],
+[ 0.132097 , 4 , 3 , 32 ],
+[ 0.132109 , 4 , 3 , 33 ],
+[ 0.132387 , 6 , 5 , 12 ],
+[ 0.132399 , 6 , 5 , 13 ],
+[ 0.132412 , 6 , 5 , 14 ],
+[ 0.132701 , 8 , 7 , 12 ],
+[ 0.132714 , 8 , 7 , 13 ],
+[ 0.132723 , 3 , 2 , 24 ],
+[ 0.132727 , 8 , 7 , 14 ],
+[ 0.132735 , 3 , 2 , 25 ],
+[ 0.132739 , 8 , 7 , 15 ],
+[ 0.132747 , 3 , 2 , 26 ],
+[ 0.132751 , 8 , 7 , 16 ],
+[ 0.132760 , 3 , 2 , 27 ],
+[ 0.132764 , 8 , 7 , 17 ],
+[ 0.132772 , 3 , 2 , 28 ],
+[ 0.132784 , 3 , 2 , 29 ],
+[ 0.132796 , 3 , 2 , 30 ],
+[ 0.132809 , 3 , 2 , 31 ],
+[ 0.132821 , 3 , 2 , 32 ],
+[ 0.132907 , 7 , 6 , 12 ],
+[ 0.132920 , 7 , 6 , 13 ],
+[ 0.132932 , 7 , 6 , 14 ],
+[ 0.132944 , 7 , 6 , 15 ],
+[ 0.132957 , 7 , 6 , 16 ],
+[ 0.132969 , 7 , 6 , 17 ],
+[ 0.134138 , 12 , 11 , 12 ],
+[ 0.134162 , 14 , 13 , 12 ],
+[ 0.134377 , 13 , 12 , 12 ],
+[ 0.135972 , 19 , 0 , 26 ],
+[ 0.135986 , 19 , 0 , 27 ],
+[ 0.135997 , 19 , 0 , 28 ],
+[ 0.136011 , 19 , 0 , 29 ],
+[ 0.136023 , 19 , 0 , 30 ],
+[ 0.136034 , 19 , 0 , 31 ],
+[ 0.136048 , 19 , 0 , 32 ],
+[ 0.136059 , 19 , 0 , 33 ],
+[ 0.136071 , 19 , 0 , 34 ],
+[ 0.136096 , 20 , 1 , 22 ],
+[ 0.136110 , 20 , 1 , 23 ],
+[ 0.136122 , 20 , 1 , 24 ],
+[ 0.136184 , 21 , 3 , 26 ],
+[ 0.136197 , 21 , 3 , 27 ],
+[ 0.136209 , 21 , 3 , 28 ],
+[ 0.136222 , 21 , 3 , 29 ],
+[ 0.136235 , 21 , 3 , 30 ],
+[ 0.136246 , 21 , 3 , 31 ],
+[ 0.136259 , 21 , 3 , 32 ],
+[ 0.136271 , 21 , 3 , 33 ],
+[ 0.137197 , 24 , 0 , 26 ],
+[ 0.137210 , 24 , 0 , 27 ],
+[ 0.137222 , 24 , 0 , 28 ],
+[ 0.137235 , 24 , 0 , 29 ],
+[ 0.137247 , 24 , 0 , 30 ],
+[ 0.137259 , 24 , 0 , 31 ],
+[ 0.137272 , 24 , 0 , 32 ],
+[ 0.137284 , 24 , 0 , 33 ],
+[ 0.137296 , 24 , 0 , 34 ],
+[ 0.137321 , 25 , 1 , 22 ],
+[ 0.137334 , 25 , 1 , 23 ],
+[ 0.137347 , 25 , 1 , 24 ],
+[ 0.137409 , 26 , 3 , 26 ],
+[ 0.137422 , 26 , 3 , 27 ],
+[ 0.137434 , 26 , 3 , 28 ],
+[ 0.137447 , 26 , 3 , 29 ],
+[ 0.137459 , 26 , 3 , 30 ],
+[ 0.137471 , 26 , 3 , 31 ],
+[ 0.137484 , 26 , 3 , 32 ],
+[ 0.137496 , 26 , 3 , 33 ],
+[ 0.137898 , 28 , 3 , 26 ],
+[ 0.137911 , 28 , 3 , 27 ],
+[ 0.137924 , 28 , 3 , 28 ],
+[ 0.137936 , 28 , 3 , 29 ],
+[ 0.137949 , 28 , 3 , 30 ],
+[ 0.137960 , 28 , 3 , 31 ],
+[ 0.137973 , 28 , 3 , 32 ],
+[ 0.137986 , 28 , 3 , 33 ],
+[ 0.138388 , 30 , 3 , 26 ],
+[ 0.138401 , 30 , 3 , 27 ],
+[ 0.138413 , 30 , 3 , 28 ],
+[ 0.138426 , 30 , 3 , 29 ],
+[ 0.138438 , 30 , 3 , 30 ],
+[ 0.138450 , 30 , 3 , 31 ],
+[ 0.138463 , 30 , 3 , 32 ],
+[ 0.138475 , 30 , 3 , 33 ],
+[ 0.138784 , 9 , 8 , 12 ],
+[ 0.139156 , 32 , 0 , 26 ],
+[ 0.139169 , 32 , 0 , 27 ],
+[ 0.139181 , 32 , 0 , 28 ],
+[ 0.139194 , 32 , 0 , 29 ],
+[ 0.139206 , 32 , 0 , 30 ],
+[ 0.139218 , 32 , 0 , 31 ],
+[ 0.139231 , 32 , 0 , 32 ],
+[ 0.139243 , 32 , 0 , 33 ],
+[ 0.139255 , 32 , 0 , 34 ],
+[ 0.139280 , 33 , 1 , 22 ],
+[ 0.139293 , 33 , 1 , 23 ],
+[ 0.139306 , 33 , 1 , 24 ],
+[ 0.139368 , 34 , 3 , 26 ],
+[ 0.139381 , 34 , 3 , 27 ],
+[ 0.139393 , 34 , 3 , 28 ],
+[ 0.139406 , 34 , 3 , 29 ],
+[ 0.139418 , 34 , 3 , 30 ],
+[ 0.139430 , 34 , 3 , 31 ],
+[ 0.139443 , 34 , 3 , 32 ],
+[ 0.139455 , 34 , 3 , 33 ],
+[ 0.140803 , 36 , 2 , 24 ],
+[ 0.140815 , 36 , 2 , 25 ],
+[ 0.140827 , 36 , 2 , 26 ],
+[ 0.140837 , 40 , 3 , 26 ],
+[ 0.140840 , 36 , 2 , 27 ],
+[ 0.140850 , 40 , 3 , 27 ],
+[ 0.140852 , 36 , 2 , 28 ],
+[ 0.140862 , 40 , 3 , 28 ],
+[ 0.140864 , 36 , 2 , 29 ],
+[ 0.140875 , 40 , 3 , 29 ],
+[ 0.140876 , 36 , 2 , 30 ],
+[ 0.140887 , 40 , 3 , 30 ],
+[ 0.140889 , 36 , 2 , 31 ],
+[ 0.140899 , 40 , 3 , 31 ],
+[ 0.140901 , 36 , 2 , 32 ],
+[ 0.140912 , 40 , 3 , 32 ],
+[ 0.140924 , 40 , 3 , 33 ],
+[ 0.142209 , 1 , 0 , 35 ],
+[ 0.142215 , 1 , 0 , 36 ],
+[ 0.142220 , 1 , 0 , 37 ],
+[ 0.142225 , 1 , 0 , 38 ],
+[ 0.142666 , 4 , 3 , 34 ],
+[ 0.142671 , 4 , 3 , 35 ],
+[ 0.142676 , 4 , 3 , 36 ],
+[ 0.142681 , 4 , 3 , 37 ],
+[ 0.142740 , 2 , 1 , 25 ],
+[ 0.142745 , 2 , 1 , 26 ],
+[ 0.143371 , 3 , 2 , 33 ],
+[ 0.143376 , 3 , 2 , 34 ],
+[ 0.143382 , 3 , 2 , 35 ],
+[ 0.143387 , 3 , 2 , 36 ],
+[ 0.143444 , 6 , 5 , 15 ],
+[ 0.143449 , 6 , 5 , 16 ],
+[ 0.143757 , 8 , 7 , 18 ],
+[ 0.143762 , 8 , 7 , 19 ],
+[ 0.143767 , 8 , 7 , 20 ],
+[ 0.143968 , 7 , 6 , 18 ],
+[ 0.143974 , 7 , 6 , 19 ],
+[ 0.143978 , 7 , 6 , 20 ],
+[ 0.145210 , 12 , 11 , 13 ],
+[ 0.145223 , 14 , 13 , 13 ],
+[ 0.145224 , 12 , 11 , 14 ],
+[ 0.145236 , 12 , 11 , 15 ],
+[ 0.145237 , 14 , 13 , 14 ],
+[ 0.145249 , 14 , 13 , 15 ],
+[ 0.145262 , 14 , 13 , 16 ],
+[ 0.145275 , 14 , 13 , 17 ],
+[ 0.145287 , 14 , 13 , 18 ],
+[ 0.145449 , 13 , 12 , 13 ],
+[ 0.145462 , 13 , 12 , 14 ],
+[ 0.145475 , 13 , 12 , 15 ],
+[ 0.145488 , 13 , 12 , 16 ],
+[ 0.145501 , 13 , 12 , 17 ],
+[ 0.145514 , 13 , 12 , 18 ],
+[ 0.146616 , 19 , 0 , 35 ],
+[ 0.146622 , 19 , 0 , 36 ],
+[ 0.146627 , 19 , 0 , 37 ],
+[ 0.146632 , 19 , 0 , 38 ],
+[ 0.146828 , 21 , 3 , 34 ],
+[ 0.146833 , 21 , 3 , 35 ],
+[ 0.146838 , 21 , 3 , 36 ],
+[ 0.146843 , 21 , 3 , 37 ],
+[ 0.147147 , 20 , 1 , 25 ],
+[ 0.147152 , 20 , 1 , 26 ],
+[ 0.147841 , 24 , 0 , 35 ],
+[ 0.147847 , 24 , 0 , 36 ],
+[ 0.147852 , 24 , 0 , 37 ],
+[ 0.147857 , 24 , 0 , 38 ],
+[ 0.148053 , 26 , 3 , 34 ],
+[ 0.148058 , 26 , 3 , 35 ],
+[ 0.148063 , 26 , 3 , 36 ],
+[ 0.148068 , 26 , 3 , 37 ],
+[ 0.148372 , 25 , 1 , 25 ],
+[ 0.148377 , 25 , 1 , 26 ],
+[ 0.148542 , 28 , 3 , 34 ],
+[ 0.148547 , 28 , 3 , 35 ],
+[ 0.148552 , 28 , 3 , 36 ],
+[ 0.148557 , 28 , 3 , 37 ],
+[ 0.149032 , 30 , 3 , 34 ],
+[ 0.149037 , 30 , 3 , 35 ],
+[ 0.149042 , 30 , 3 , 36 ],
+[ 0.149047 , 30 , 3 , 37 ],
+[ 0.149195 , 17 , 16 , 29 ],
+[ 0.149800 , 32 , 0 , 35 ],
+[ 0.149806 , 32 , 0 , 36 ],
+[ 0.149811 , 32 , 0 , 37 ],
+[ 0.149816 , 32 , 0 , 38 ],
+[ 0.150012 , 34 , 3 , 34 ],
+[ 0.150017 , 34 , 3 , 35 ],
+[ 0.150022 , 34 , 3 , 36 ],
+[ 0.150027 , 34 , 3 , 37 ],
+[ 0.150331 , 33 , 1 , 25 ],
+[ 0.150336 , 33 , 1 , 26 ],
+[ 0.151451 , 36 , 2 , 33 ],
+[ 0.151456 , 36 , 2 , 34 ],
+[ 0.151462 , 36 , 2 , 35 ],
+[ 0.151467 , 36 , 2 , 36 ],
+[ 0.151481 , 40 , 3 , 34 ],
+[ 0.151486 , 40 , 3 , 35 ],
+[ 0.151491 , 40 , 3 , 36 ],
+[ 0.151496 , 40 , 3 , 37 ],
+[ 0.151863 , 9 , 8 , 13 ],
+[ 0.153285 , 1 , 0 , 39 ],
+[ 0.153298 , 1 , 0 , 40 ],
+[ 0.153299 , 1 , 0 , 41 ],
+[ 0.153833 , 2 , 1 , 27 ],
+[ 0.153846 , 2 , 1 , 28 ],
+[ 0.153858 , 2 , 1 , 29 ],
+[ 0.153871 , 2 , 1 , 30 ],
+[ 0.153883 , 2 , 1 , 31 ],
+[ 0.153895 , 2 , 1 , 32 ],
+[ 0.154383 , 8 , 7 , 21 ],
+[ 0.154396 , 8 , 7 , 22 ],
+[ 0.154408 , 8 , 7 , 23 ],
+[ 0.154420 , 8 , 7 , 24 ],
+[ 0.154450 , 3 , 2 , 37 ],
+[ 0.154462 , 3 , 2 , 38 ],
+[ 0.154469 , 6 , 5 , 17 ],
+[ 0.154475 , 3 , 2 , 39 ],
+[ 0.154475 , 6 , 5 , 18 ],
+[ 0.154487 , 3 , 2 , 40 ],
+[ 0.154499 , 3 , 2 , 41 ],
+[ 0.154512 , 3 , 2 , 42 ],
+[ 0.154524 , 3 , 2 , 43 ],
+[ 0.154634 , 7 , 6 , 21 ],
+[ 0.154647 , 7 , 6 , 22 ],
+[ 0.154659 , 7 , 6 , 23 ],
+[ 0.154672 , 7 , 6 , 24 ],
+[ 0.154684 , 7 , 6 , 25 ],
+[ 0.154696 , 7 , 6 , 26 ],
+[ 0.154709 , 7 , 6 , 27 ],
+[ 0.154721 , 7 , 6 , 28 ],
+[ 0.154733 , 7 , 6 , 29 ],
+[ 0.156276 , 12 , 11 , 16 ],
+[ 0.156283 , 12 , 11 , 17 ],
+[ 0.156286 , 14 , 13 , 19 ],
+[ 0.156292 , 14 , 13 , 20 ],
+[ 0.156297 , 14 , 13 , 21 ],
+[ 0.156516 , 13 , 12 , 19 ],
+[ 0.156523 , 13 , 12 , 20 ],
+[ 0.156529 , 13 , 12 , 21 ],
+[ 0.157692 , 19 , 0 , 39 ],
+[ 0.157706 , 19 , 0 , 40 ],
+[ 0.157706 , 19 , 0 , 41 ],
+[ 0.158241 , 20 , 1 , 27 ],
+[ 0.158253 , 20 , 1 , 28 ],
+[ 0.158266 , 20 , 1 , 29 ],
+[ 0.158278 , 20 , 1 , 30 ],
+[ 0.158291 , 20 , 1 , 31 ],
+[ 0.158303 , 20 , 1 , 32 ],
+[ 0.158917 , 24 , 0 , 39 ],
+[ 0.158930 , 24 , 0 , 40 ],
+[ 0.158931 , 24 , 0 , 41 ],
+[ 0.159465 , 25 , 1 , 27 ],
+[ 0.159478 , 25 , 1 , 28 ],
+[ 0.159490 , 25 , 1 , 29 ],
+[ 0.159503 , 25 , 1 , 30 ],
+[ 0.159515 , 25 , 1 , 31 ],
+[ 0.159527 , 25 , 1 , 32 ],
+[ 0.160238 , 17 , 16 , 30 ],
+[ 0.160643 , 15 , 14 , 12 ],
+[ 0.160876 , 32 , 0 , 39 ],
+[ 0.160889 , 32 , 0 , 40 ],
+[ 0.160890 , 32 , 0 , 41 ],
+[ 0.161424 , 33 , 1 , 27 ],
+[ 0.161437 , 33 , 1 , 28 ],
+[ 0.161449 , 33 , 1 , 29 ],
+[ 0.161462 , 33 , 1 , 30 ],
+[ 0.161474 , 33 , 1 , 31 ],
+[ 0.161486 , 33 , 1 , 32 ],
+[ 0.162530 , 36 , 2 , 37 ],
+[ 0.162542 , 36 , 2 , 38 ],
+[ 0.162555 , 36 , 2 , 39 ],
+[ 0.162567 , 36 , 2 , 40 ],
+[ 0.162579 , 36 , 2 , 41 ],
+[ 0.162592 , 36 , 2 , 42 ],
+[ 0.162604 , 36 , 2 , 43 ],
+[ 0.162904 , 9 , 8 , 14 ],
+[ 0.164347 , 1 , 0 , 42 ],
+[ 0.164353 , 1 , 0 , 43 ],
+[ 0.164889 , 2 , 1 , 33 ],
+[ 0.164895 , 2 , 1 , 34 ],
+[ 0.164901 , 2 , 1 , 35 ],
+[ 0.165168 , 3 , 2 , 44 ],
+[ 0.165173 , 3 , 2 , 45 ],
+[ 0.165178 , 3 , 2 , 46 ],
+[ 0.165199 , 3 , 2 , 47 ],
+[ 0.165211 , 3 , 2 , 48 ],
+[ 0.165224 , 3 , 2 , 49 ],
+[ 0.165236 , 3 , 2 , 50 ],
+[ 0.165248 , 3 , 2 , 51 ],
+[ 0.165280 , 7 , 6 , 30 ],
+[ 0.165286 , 7 , 6 , 31 ],
+[ 0.165290 , 7 , 6 , 32 ],
+[ 0.165295 , 7 , 6 , 33 ],
+[ 0.165404 , 8 , 7 , 25 ],
+[ 0.165410 , 8 , 7 , 26 ],
+[ 0.165492 , 6 , 5 , 19 ],
+[ 0.166940 , 14 , 13 , 22 ],
+[ 0.166952 , 14 , 13 , 23 ],
+[ 0.166965 , 14 , 13 , 24 ],
+[ 0.166977 , 14 , 13 , 25 ],
+[ 0.166989 , 14 , 13 , 26 ],
+[ 0.167002 , 14 , 13 , 27 ],
+[ 0.167014 , 14 , 13 , 28 ],
+[ 0.167027 , 14 , 13 , 29 ],
+[ 0.167039 , 14 , 13 , 30 ],
+[ 0.167318 , 12 , 11 , 18 ],
+[ 0.167583 , 13 , 12 , 22 ],
+[ 0.167596 , 13 , 12 , 23 ],
+[ 0.167610 , 13 , 12 , 24 ],
+[ 0.167623 , 13 , 12 , 25 ],
+[ 0.167635 , 13 , 12 , 26 ],
+[ 0.167648 , 13 , 12 , 27 ],
+[ 0.168755 , 19 , 0 , 42 ],
+[ 0.168760 , 19 , 0 , 43 ],
+[ 0.169296 , 20 , 1 , 33 ],
+[ 0.169302 , 20 , 1 , 34 ],
+[ 0.169308 , 20 , 1 , 35 ],
+[ 0.169979 , 24 , 0 , 42 ],
+[ 0.169985 , 24 , 0 , 43 ],
+[ 0.170521 , 25 , 1 , 33 ],
+[ 0.170527 , 25 , 1 , 34 ],
+[ 0.170533 , 25 , 1 , 35 ],
+[ 0.171938 , 32 , 0 , 42 ],
+[ 0.171944 , 32 , 0 , 43 ],
+[ 0.172480 , 33 , 1 , 33 ],
+[ 0.172486 , 33 , 1 , 34 ],
+[ 0.172492 , 33 , 1 , 35 ],
+[ 0.173248 , 36 , 2 , 44 ],
+[ 0.173253 , 36 , 2 , 45 ],
+[ 0.173258 , 36 , 2 , 46 ],
+[ 0.173279 , 36 , 2 , 47 ],
+[ 0.173291 , 36 , 2 , 48 ],
+[ 0.173304 , 36 , 2 , 49 ],
+[ 0.173316 , 36 , 2 , 50 ],
+[ 0.173328 , 36 , 2 , 51 ],
+[ 0.174314 , 17 , 16 , 31 ],
+[ 0.175402 , 1 , 0 , 44 ],
+[ 0.175545 , 2 , 1 , 36 ],
+[ 0.175558 , 2 , 1 , 37 ],
+[ 0.175570 , 2 , 1 , 38 ],
+[ 0.175582 , 2 , 1 , 39 ],
+[ 0.175595 , 2 , 1 , 40 ],
+[ 0.175607 , 2 , 1 , 41 ],
+[ 0.175619 , 2 , 1 , 42 ],
+[ 0.175632 , 2 , 1 , 43 ],
+[ 0.175644 , 2 , 1 , 44 ],
+[ 0.175823 , 3 , 2 , 52 ],
+[ 0.175831 , 3 , 2 , 53 ],
+[ 0.175933 , 7 , 6 , 34 ],
+[ 0.175945 , 7 , 6 , 35 ],
+[ 0.175955 , 9 , 8 , 15 ],
+[ 0.175957 , 7 , 6 , 36 ],
+[ 0.175970 , 7 , 6 , 37 ],
+[ 0.175982 , 7 , 6 , 38 ],
+[ 0.175994 , 7 , 6 , 39 ],
+[ 0.176007 , 7 , 6 , 40 ],
+[ 0.176019 , 7 , 6 , 41 ],
+[ 0.176031 , 7 , 6 , 42 ],
+[ 0.176431 , 8 , 7 , 27 ],
+[ 0.176437 , 8 , 7 , 28 ],
+[ 0.176444 , 7 , 6 , 43 ],
+[ 0.176457 , 7 , 6 , 44 ],
+[ 0.176470 , 7 , 6 , 45 ],
+[ 0.176535 , 6 , 5 , 20 ],
+[ 0.177594 , 14 , 13 , 31 ],
+[ 0.177600 , 14 , 13 , 32 ],
+[ 0.177605 , 14 , 13 , 33 ],
+[ 0.177610 , 14 , 13 , 34 ],
+[ 0.178374 , 12 , 11 , 19 ],
+[ 0.178379 , 12 , 11 , 20 ],
+[ 0.178653 , 13 , 12 , 28 ],
+[ 0.178660 , 13 , 12 , 29 ],
+[ 0.178666 , 13 , 12 , 30 ],
+[ 0.179810 , 19 , 0 , 44 ],
+[ 0.179953 , 20 , 1 , 36 ],
+[ 0.179965 , 20 , 1 , 37 ],
+[ 0.179977 , 20 , 1 , 38 ],
+[ 0.179990 , 20 , 1 , 39 ],
+[ 0.180002 , 20 , 1 , 40 ],
+[ 0.180015 , 20 , 1 , 41 ],
+[ 0.180026 , 20 , 1 , 42 ],
+[ 0.180040 , 20 , 1 , 43 ],
+[ 0.180052 , 20 , 1 , 44 ],
+[ 0.181034 , 24 , 0 , 44 ],
+[ 0.181177 , 25 , 1 , 36 ],
+[ 0.181190 , 25 , 1 , 37 ],
+[ 0.181202 , 25 , 1 , 38 ],
+[ 0.181214 , 25 , 1 , 39 ],
+[ 0.181227 , 25 , 1 , 40 ],
+[ 0.181239 , 25 , 1 , 41 ],
+[ 0.181251 , 25 , 1 , 42 ],
+[ 0.181264 , 25 , 1 , 43 ],
+[ 0.181276 , 25 , 1 , 44 ],
+[ 0.182993 , 32 , 0 , 44 ],
+[ 0.183136 , 33 , 1 , 36 ],
+[ 0.183149 , 33 , 1 , 37 ],
+[ 0.183161 , 33 , 1 , 38 ],
+[ 0.183173 , 33 , 1 , 39 ],
+[ 0.183186 , 33 , 1 , 40 ],
+[ 0.183198 , 33 , 1 , 41 ],
+[ 0.183210 , 33 , 1 , 42 ],
+[ 0.183223 , 33 , 1 , 43 ],
+[ 0.183235 , 33 , 1 , 44 ],
+[ 0.183903 , 36 , 2 , 52 ],
+[ 0.183911 , 36 , 2 , 53 ],
+[ 0.185366 , 17 , 16 , 32 ],
+[ 0.186097 , 7 , 6 , 46 ],
+[ 0.186101 , 7 , 6 , 47 ],
+[ 0.186189 , 2 , 1 , 45 ],
+[ 0.186194 , 2 , 1 , 46 ],
+[ 0.186199 , 2 , 1 , 47 ],
+[ 0.186205 , 2 , 1 , 48 ],
+[ 0.186590 , 7 , 6 , 48 ],
+[ 0.186595 , 7 , 6 , 49 ],
+[ 0.186600 , 7 , 6 , 50 ],
+[ 0.186604 , 7 , 6 , 51 ],
+[ 0.186898 , 3 , 2 , 54 ],
+[ 0.186912 , 3 , 2 , 55 ],
+[ 0.186924 , 3 , 2 , 56 ],
+[ 0.187451 , 8 , 7 , 29 ],
+[ 0.188232 , 14 , 13 , 35 ],
+[ 0.188244 , 14 , 13 , 36 ],
+[ 0.188257 , 14 , 13 , 37 ],
+[ 0.188269 , 14 , 13 , 38 ],
+[ 0.188281 , 14 , 13 , 39 ],
+[ 0.188294 , 14 , 13 , 40 ],
+[ 0.188306 , 14 , 13 , 41 ],
+[ 0.188318 , 14 , 13 , 42 ],
+[ 0.188331 , 14 , 13 , 43 ],
+[ 0.188343 , 14 , 13 , 44 ],
+[ 0.188355 , 14 , 13 , 45 ],
+[ 0.188368 , 14 , 13 , 46 ],
+[ 0.188371 , 17 , 16 , 33 ],
+[ 0.189410 , 12 , 11 , 21 ],
+[ 0.189695 , 13 , 12 , 31 ],
+[ 0.190597 , 20 , 1 , 45 ],
+[ 0.190602 , 20 , 1 , 46 ],
+[ 0.190607 , 20 , 1 , 47 ],
+[ 0.190613 , 20 , 1 , 48 ],
+[ 0.190655 , 15 , 14 , 13 ],
+[ 0.191821 , 25 , 1 , 45 ],
+[ 0.191826 , 25 , 1 , 46 ],
+[ 0.191831 , 25 , 1 , 47 ],
+[ 0.191837 , 25 , 1 , 48 ],
+[ 0.193780 , 33 , 1 , 45 ],
+[ 0.193785 , 33 , 1 , 46 ],
+[ 0.193790 , 33 , 1 , 47 ],
+[ 0.193796 , 33 , 1 , 48 ],
+[ 0.194978 , 36 , 2 , 54 ],
+[ 0.194992 , 36 , 2 , 55 ],
+[ 0.195004 , 36 , 2 , 56 ],
+[ 0.196755 , 7 , 6 , 52 ],
+[ 0.196768 , 7 , 6 , 53 ],
+[ 0.196780 , 7 , 6 , 54 ],
+[ 0.196796 , 7 , 6 , 55 ],
+[ 0.196809 , 7 , 6 , 56 ],
+[ 0.196821 , 7 , 6 , 57 ],
+[ 0.196834 , 7 , 6 , 58 ],
+[ 0.196846 , 7 , 6 , 59 ],
+[ 0.196858 , 7 , 6 , 60 ],
+[ 0.196871 , 7 , 6 , 61 ],
+[ 0.196883 , 7 , 6 , 62 ],
+[ 0.196895 , 7 , 6 , 63 ],
+[ 0.196908 , 7 , 6 , 64 ],
+[ 0.196920 , 7 , 6 , 65 ],
+[ 0.196932 , 7 , 6 , 66 ],
+[ 0.197192 , 2 , 1 , 49 ],
+[ 0.197204 , 2 , 1 , 50 ],
+[ 0.197205 , 2 , 1 , 51 ],
+[ 0.197349 , 7 , 6 , 67 ],
+[ 0.197361 , 7 , 6 , 68 ],
+[ 0.197374 , 7 , 6 , 69 ],
+[ 0.197601 , 3 , 2 , 57 ],
+[ 0.197632 , 3 , 2 , 58 ],
+[ 0.197644 , 3 , 2 , 59 ],
+[ 0.197657 , 3 , 2 , 60 ],
+[ 0.197669 , 3 , 2 , 61 ],
+[ 0.197681 , 3 , 2 , 62 ],
+[ 0.197694 , 3 , 2 , 63 ],
+[ 0.197706 , 3 , 2 , 64 ],
+[ 0.197718 , 3 , 2 , 65 ],
+[ 0.197731 , 3 , 2 , 66 ],
+[ 0.197743 , 3 , 2 , 67 ],
+[ 0.197755 , 3 , 2 , 68 ],
+[ 0.197768 , 3 , 2 , 69 ],
+[ 0.197780 , 3 , 2 , 70 ],
+[ 0.197792 , 3 , 2 , 71 ],
+[ 0.197804 , 3 , 2 , 72 ],
+[ 0.197817 , 3 , 2 , 73 ],
+[ 0.198231 , 3 , 2 , 74 ],
+[ 0.198480 , 8 , 7 , 30 ],
+[ 0.198868 , 14 , 13 , 47 ],
+[ 0.198873 , 14 , 13 , 48 ],
+[ 0.198878 , 14 , 13 , 49 ],
+[ 0.198884 , 14 , 13 , 50 ],
+[ 0.198890 , 14 , 13 , 51 ],
+[ 0.199381 , 14 , 13 , 52 ],
+[ 0.200412 , 17 , 16 , 34 ],
+[ 0.200454 , 12 , 11 , 22 ],
+[ 0.200722 , 13 , 12 , 32 ],
+[ 0.200727 , 13 , 12 , 33 ],
+[ 0.201600 , 20 , 1 , 49 ],
+[ 0.201611 , 20 , 1 , 50 ],
+[ 0.201612 , 20 , 1 , 51 ],
+[ 0.202824 , 25 , 1 , 49 ],
+[ 0.202836 , 25 , 1 , 50 ],
+[ 0.202837 , 25 , 1 , 51 ],
+[ 0.204783 , 33 , 1 , 49 ],
+[ 0.204795 , 33 , 1 , 50 ],
+[ 0.204796 , 33 , 1 , 51 ],
+[ 0.205681 , 36 , 2 , 57 ],
+[ 0.205712 , 36 , 2 , 58 ],
+[ 0.205724 , 36 , 2 , 59 ],
+[ 0.205737 , 36 , 2 , 60 ],
+[ 0.205749 , 36 , 2 , 61 ],
+[ 0.205761 , 36 , 2 , 62 ],
+[ 0.205774 , 36 , 2 , 63 ],
+[ 0.205786 , 36 , 2 , 64 ],
+[ 0.205798 , 36 , 2 , 65 ],
+[ 0.205811 , 36 , 2 , 66 ],
+[ 0.205823 , 36 , 2 , 67 ],
+[ 0.205835 , 36 , 2 , 68 ],
+[ 0.205848 , 36 , 2 , 69 ],
+[ 0.205860 , 36 , 2 , 70 ],
+[ 0.205872 , 36 , 2 , 71 ],
+[ 0.205884 , 36 , 2 , 72 ],
+[ 0.205897 , 36 , 2 , 73 ],
+[ 0.206311 , 36 , 2 , 74 ],
+[ 0.207015 , 7 , 6 , 70 ],
+[ 0.207019 , 7 , 6 , 71 ],
+[ 0.207024 , 7 , 6 , 72 ],
+[ 0.207029 , 7 , 6 , 73 ],
+[ 0.207034 , 7 , 6 , 74 ],
+[ 0.207039 , 7 , 6 , 75 ],
+[ 0.207044 , 7 , 6 , 76 ],
+[ 0.207529 , 7 , 6 , 77 ],
+[ 0.207535 , 7 , 6 , 78 ],
+[ 0.207752 , 15 , 14 , 14 ],
+[ 0.207762 , 15 , 14 , 15 ],
+[ 0.207771 , 15 , 14 , 16 ],
+[ 0.207871 , 3 , 2 , 75 ],
+[ 0.207881 , 3 , 2 , 76 ],
+[ 0.207886 , 3 , 2 , 77 ],
+[ 0.207891 , 3 , 2 , 78 ],
+[ 0.207896 , 3 , 2 , 79 ],
+[ 0.207901 , 3 , 2 , 80 ],
+[ 0.208210 , 2 , 1 , 52 ],
+[ 0.208220 , 2 , 1 , 53 ],
+[ 0.208392 , 3 , 2 , 81 ],
+[ 0.208397 , 3 , 2 , 82 ],
+[ 0.208749 , 15 , 14 , 17 ],
+[ 0.209512 , 14 , 13 , 53 ],
+[ 0.209524 , 14 , 13 , 54 ],
+[ 0.209537 , 14 , 13 , 55 ],
+[ 0.209550 , 14 , 13 , 56 ],
+[ 0.209562 , 14 , 13 , 57 ],
+[ 0.209575 , 14 , 13 , 58 ],
+[ 0.209587 , 14 , 13 , 59 ],
+[ 0.209599 , 14 , 13 , 60 ],
+[ 0.209612 , 14 , 13 , 61 ],
+[ 0.209624 , 14 , 13 , 62 ],
+[ 0.209636 , 14 , 13 , 63 ],
+[ 0.209648 , 14 , 13 , 64 ],
+[ 0.209661 , 14 , 13 , 65 ],
+[ 0.209673 , 14 , 13 , 66 ],
+[ 0.209685 , 14 , 13 , 67 ],
+[ 0.209933 , 14 , 13 , 68 ],
+[ 0.210447 , 14 , 13 , 69 ],
+[ 0.210460 , 14 , 13 , 70 ],
+[ 0.210746 , 15 , 14 , 18 ],
+[ 0.211437 , 17 , 16 , 35 ],
+[ 0.211755 , 13 , 12 , 34 ],
+[ 0.212618 , 20 , 1 , 52 ],
+[ 0.212628 , 20 , 1 , 53 ],
+[ 0.213842 , 25 , 1 , 52 ],
+[ 0.213852 , 25 , 1 , 53 ],
+[ 0.215801 , 33 , 1 , 52 ],
+[ 0.215811 , 33 , 1 , 53 ],
+[ 0.215951 , 36 , 2 , 75 ],
+[ 0.215961 , 36 , 2 , 76 ],
+[ 0.215966 , 36 , 2 , 77 ],
+[ 0.215971 , 36 , 2 , 78 ],
+[ 0.215976 , 36 , 2 , 79 ],
+[ 0.215981 , 36 , 2 , 80 ],
+[ 0.216472 , 36 , 2 , 81 ],
+[ 0.216477 , 36 , 2 , 82 ],
+[ 0.217229 , 7 , 6 , 79 ],
+[ 0.217242 , 7 , 6 , 80 ],
+[ 0.217254 , 7 , 6 , 81 ],
+[ 0.217266 , 7 , 6 , 82 ],
+[ 0.217279 , 7 , 6 , 83 ],
+[ 0.217291 , 7 , 6 , 84 ],
+[ 0.217303 , 7 , 6 , 85 ],
+[ 0.217316 , 7 , 6 , 86 ],
+[ 0.217328 , 7 , 6 , 87 ],
+[ 0.217340 , 7 , 6 , 88 ],
+[ 0.217352 , 7 , 6 , 89 ],
+[ 0.217365 , 7 , 6 , 90 ],
+[ 0.217377 , 7 , 6 , 91 ],
+[ 0.217389 , 7 , 6 , 92 ],
+[ 0.217633 , 7 , 6 , 93 ],
+[ 0.217646 , 7 , 6 , 94 ],
+[ 0.217658 , 7 , 6 , 95 ],
+[ 0.217671 , 7 , 6 , 96 ],
+[ 0.217683 , 7 , 6 , 97 ],
+[ 0.217695 , 7 , 6 , 98 ],
+[ 0.217707 , 7 , 6 , 99 ],
+[ 0.218529 , 3 , 2 , 83 ],
+[ 0.218542 , 3 , 2 , 84 ],
+[ 0.218554 , 3 , 2 , 85 ],
+[ 0.218566 , 3 , 2 , 86 ],
+[ 0.218579 , 3 , 2 , 87 ],
+[ 0.218591 , 3 , 2 , 88 ],
+[ 0.218603 , 3 , 2 , 89 ],
+[ 0.218616 , 3 , 2 , 90 ],
+[ 0.218628 , 3 , 2 , 91 ],
+[ 0.219235 , 2 , 1 , 54 ],
+[ 0.219788 , 14 , 13 , 71 ],
+[ 0.219794 , 14 , 13 , 72 ],
+[ 0.219800 , 14 , 13 , 73 ],
+[ 0.219805 , 14 , 13 , 74 ],
+[ 0.219810 , 14 , 13 , 75 ],
+[ 0.220024 , 9 , 8 , 16 ],
+[ 0.220499 , 14 , 13 , 76 ],
+[ 0.220505 , 14 , 13 , 77 ],
+[ 0.220510 , 14 , 13 , 78 ],
+[ 0.221499 , 14 , 13 , 79 ],
+[ 0.222785 , 13 , 12 , 35 ],
+[ 0.223643 , 20 , 1 , 54 ],
+[ 0.224867 , 25 , 1 , 54 ],
+[ 0.226481 , 17 , 16 , 36 ],
+[ 0.226609 , 36 , 2 , 83 ],
+[ 0.226622 , 36 , 2 , 84 ],
+[ 0.226634 , 36 , 2 , 85 ],
+[ 0.226646 , 36 , 2 , 86 ],
+[ 0.226659 , 36 , 2 , 87 ],
+[ 0.226671 , 36 , 2 , 88 ],
+[ 0.226683 , 36 , 2 , 89 ],
+[ 0.226696 , 36 , 2 , 90 ],
+[ 0.226708 , 36 , 2 , 91 ],
+[ 0.226826 , 33 , 1 , 54 ],
+[ 0.227480 , 17 , 16 , 37 ],
+[ 0.227491 , 7 , 6 , 100 ],
+[ 0.227496 , 7 , 6 , 101 ],
+[ 0.227501 , 7 , 6 , 102 ],
+[ 0.227505 , 7 , 6 , 103 ],
+[ 0.227511 , 7 , 6 , 104 ],
+[ 0.227515 , 7 , 6 , 105 ],
+[ 0.227521 , 7 , 6 , 106 ],
+[ 0.228002 , 7 , 6 , 107 ],
+[ 0.228007 , 7 , 6 , 108 ],
+[ 0.228012 , 7 , 6 , 109 ],
+[ 0.228017 , 7 , 6 , 110 ],
+[ 0.229162 , 3 , 2 , 92 ],
+[ 0.229167 , 3 , 2 , 93 ],
+[ 0.229172 , 3 , 2 , 94 ],
+[ 0.229177 , 3 , 2 , 95 ],
+[ 0.229182 , 3 , 2 , 96 ],
+[ 0.230423 , 14 , 13 , 80 ],
+[ 0.230435 , 14 , 13 , 81 ],
+[ 0.230448 , 14 , 13 , 82 ],
+[ 0.230460 , 14 , 13 , 83 ],
+[ 0.230472 , 14 , 13 , 84 ],
+[ 0.230485 , 14 , 13 , 85 ],
+[ 0.230497 , 14 , 13 , 86 ],
+[ 0.230509 , 14 , 13 , 87 ],
+[ 0.230522 , 14 , 13 , 88 ],
+[ 0.230534 , 14 , 13 , 89 ],
+[ 0.230547 , 14 , 13 , 90 ],
+[ 0.230559 , 14 , 13 , 91 ],
+[ 0.230571 , 14 , 13 , 92 ],
+[ 0.231547 , 14 , 13 , 93 ],
+[ 0.231582 , 14 , 13 , 94 ],
+[ 0.231594 , 14 , 13 , 95 ],
+[ 0.231607 , 14 , 13 , 96 ],
+[ 0.235105 , 9 , 8 , 17 ],
+[ 0.237242 , 36 , 2 , 92 ],
+[ 0.237247 , 36 , 2 , 93 ],
+[ 0.237252 , 36 , 2 , 94 ],
+[ 0.237257 , 36 , 2 , 95 ],
+[ 0.237262 , 36 , 2 , 96 ],
+[ 0.239034 , 7 , 6 , 111 ],
+[ 0.239039 , 7 , 6 , 112 ],
+[ 0.241063 , 14 , 13 , 97 ],
+[ 0.241069 , 14 , 13 , 98 ],
+[ 0.241074 , 14 , 13 , 99 ],
+[ 0.241080 , 14 , 13 , 100 ],
+[ 0.241086 , 14 , 13 , 101 ],
+[ 0.241584 , 14 , 13 , 102 ],
+[ 0.241589 , 14 , 13 , 103 ],
+[ 0.242612 , 14 , 13 , 104 ],
+[ 0.242617 , 14 , 13 , 105 ],
+[ 0.246144 , 9 , 8 , 18 ],
+[ 0.247826 , 15 , 14 , 19 ],
+[ 0.247838 , 15 , 14 , 20 ],
+[ 0.250063 , 7 , 6 , 113 ],
+[ 0.253635 , 14 , 13 , 106 ],
+[ 0.258191 , 9 , 8 , 19 ],
+[ 0.261088 , 7 , 6 , 114 ],
+[ 0.263517 , 17 , 16 , 38 ],
+[ 0.264662 , 14 , 13 , 107 ],
+[ 0.264666 , 14 , 13 , 108 ],
+[ 0.269219 , 9 , 8 , 20 ],
+[ 0.275699 , 14 , 13 , 109 ],
+[ 0.280263 , 9 , 8 , 21 ],
+[ 0.281564 , 17 , 16 , 39 ],
+[ 0.286749 , 14 , 13 , 110 ],
+[ 0.287828 , 15 , 14 , 21 ],
+[ 0.288581 , 17 , 16 , 40 ],
+[ 0.292811 , 15 , 14 , 22 ],
+[ 0.294305 , 9 , 8 , 22 ],
+[ 0.299330 , 5 , 4 , 11 ],
+[ 0.303492 , 22 , 4 , 11 ],
+[ 0.305331 , 9 , 8 , 23 ],
+[ 0.307410 , 38 , 4 , 11 ],
+[ 0.311379 , 5 , 4 , 12 ],
+[ 0.315542 , 22 , 4 , 12 ],
+[ 0.317363 , 9 , 8 , 24 ],
+[ 0.319460 , 38 , 4 , 12 ],
+[ 0.321204 , 10 , 9 , 12 ],
+[ 0.321214 , 10 , 9 , 13 ],
+[ 0.321223 , 10 , 9 , 14 ],
+[ 0.321232 , 10 , 9 , 15 ],
+[ 0.321241 , 10 , 9 , 16 ],
+[ 0.321250 , 10 , 9 , 17 ],
+[ 0.321449 , 11 , 10 , 12 ],
+[ 0.321458 , 11 , 10 , 13 ],
+[ 0.321468 , 11 , 10 , 14 ],
+[ 0.321476 , 11 , 10 , 15 ],
+[ 0.321484 , 11 , 10 , 16 ],
+[ 0.321492 , 11 , 10 , 17 ],
+[ 0.322204 , 10 , 9 , 18 ],
+[ 0.322216 , 10 , 9 , 19 ],
+[ 0.322228 , 10 , 9 , 20 ],
+[ 0.322449 , 11 , 10 , 18 ],
+[ 0.322454 , 11 , 10 , 19 ],
+[ 0.322467 , 11 , 10 , 20 ],
+[ 0.322479 , 11 , 10 , 21 ],
+[ 0.323207 , 10 , 9 , 21 ],
+[ 0.323452 , 11 , 10 , 22 ],
+[ 0.329399 , 9 , 8 , 25 ],
+[ 0.329881 , 15 , 14 , 23 ],
+[ 0.330880 , 15 , 14 , 24 ],
+[ 0.331878 , 15 , 14 , 25 ],
+[ 0.332442 , 5 , 4 , 13 ],
+[ 0.332879 , 15 , 14 , 26 ],
+[ 0.336604 , 22 , 4 , 13 ],
+[ 0.340440 , 9 , 8 , 26 ],
+[ 0.340522 , 38 , 4 , 13 ],
+[ 0.345499 , 5 , 4 , 14 ],
+[ 0.348623 , 17 , 16 , 41 ],
+[ 0.349661 , 22 , 4 , 14 ],
+[ 0.349955 , 15 , 14 , 27 ],
+[ 0.352492 , 9 , 8 , 27 ],
+[ 0.353579 , 38 , 4 , 14 ],
+[ 0.354651 , 17 , 16 , 42 ],
+[ 0.358940 , 15 , 14 , 28 ],
+[ 0.360631 , 17 , 16 , 43 ],
+[ 0.364488 , 9 , 8 , 28 ],
+[ 0.375534 , 9 , 8 , 29 ],
+[ 0.386573 , 9 , 8 , 30 ],
+[ 0.386687 , 17 , 16 , 44 ],
+[ 0.389258 , 10 , 9 , 22 ],
+[ 0.389271 , 10 , 9 , 23 ],
+[ 0.389549 , 11 , 10 , 23 ],
+[ 0.394968 , 15 , 14 , 29 ],
+[ 0.397603 , 9 , 8 , 31 ],
+[ 0.399717 , 17 , 16 , 45 ],
+[ 0.402722 , 17 , 16 , 46 ],
+[ 0.408635 , 9 , 8 , 32 ],
+[ 0.408958 , 15 , 14 , 30 ],
+[ 0.417770 , 17 , 16 , 47 ],
+[ 0.418766 , 17 , 16 , 48 ],
+[ 0.420669 , 9 , 8 , 33 ],
+[ 0.431700 , 9 , 8 , 34 ],
+[ 0.443731 , 9 , 8 , 35 ],
+[ 0.444978 , 15 , 14 , 31 ],
+[ 0.454760 , 9 , 8 , 36 ],
+[ 0.455946 , 10 , 9 , 24 ],
+[ 0.455958 , 10 , 9 , 25 ],
+[ 0.456215 , 11 , 10 , 24 ],
+[ 0.456227 , 11 , 10 , 25 ],
+[ 0.464986 , 15 , 14 , 32 ],
+[ 0.466797 , 9 , 8 , 37 ],
+[ 0.478832 , 9 , 8 , 38 ],
+[ 0.479789 , 17 , 16 , 49 ],
+[ 0.484058 , 15 , 14 , 33 ],
+[ 0.484067 , 15 , 14 , 34 ],
+[ 0.485063 , 15 , 14 , 35 ],
+[ 0.486658 , 15 , 14 , 36 ],
+[ 0.489073 , 15 , 14 , 37 ],
+[ 0.489868 , 9 , 8 , 39 ],
+[ 0.500907 , 9 , 8 , 40 ],
+[ 0.512941 , 9 , 8 , 41 ],
+[ 0.522148 , 15 , 14 , 38 ],
+[ 0.522617 , 10 , 9 , 26 ],
+[ 0.522629 , 10 , 9 , 27 ],
+[ 0.522673 , 16 , 15 , 6 ],
+[ 0.522894 , 11 , 10 , 26 ],
+[ 0.522906 , 11 , 10 , 27 ],
+[ 0.541144 , 15 , 14 , 39 ],
+[ 0.550187 , 16 , 15 , 7 ],
+[ 0.550370 , 16 , 15 , 8 ],
+[ 0.556560 , 5 , 4 , 15 ],
+[ 0.558045 , 16 , 15 , 9 ],
+[ 0.560722 , 22 , 4 , 15 ],
+[ 0.564640 , 38 , 4 , 15 ],
+[ 0.576158 , 15 , 14 , 40 ],
+[ 0.589274 , 10 , 9 , 28 ],
+[ 0.589286 , 10 , 9 , 29 ],
+[ 0.589551 , 11 , 10 , 28 ],
+[ 0.589563 , 11 , 10 , 29 ],
+[ 0.597650 , 16 , 15 , 10 ],
+[ 0.606261 , 15 , 14 , 41 ],
+[ 0.606270 , 15 , 14 , 42 ],
+[ 0.608275 , 15 , 14 , 43 ],
+[ 0.608643 , 16 , 15 , 11 ],
+[ 0.609273 , 15 , 14 , 44 ],
+[ 0.624328 , 15 , 14 , 45 ],
+[ 0.628820 , 17 , 16 , 50 ],
+[ 0.635577 , 5 , 4 , 16 ],
+[ 0.636544 , 9 , 8 , 42 ],
+[ 0.639739 , 22 , 4 , 16 ],
+[ 0.642609 , 16 , 15 , 12 ],
+[ 0.643657 , 38 , 4 , 16 ],
+[ 0.646622 , 5 , 4 , 17 ],
+[ 0.648590 , 9 , 8 , 43 ],
+[ 0.650784 , 22 , 4 , 17 ],
+[ 0.654702 , 38 , 4 , 17 ],
+[ 0.655945 , 10 , 9 , 30 ],
+[ 0.655957 , 10 , 9 , 31 ],
+[ 0.656238 , 11 , 10 , 30 ],
+[ 0.656250 , 11 , 10 , 31 ],
+[ 0.658655 , 5 , 4 , 18 ],
+[ 0.660614 , 9 , 8 , 44 ],
+[ 0.662817 , 22 , 4 , 18 ],
+[ 0.664350 , 15 , 14 , 46 ],
+[ 0.666735 , 38 , 4 , 18 ],
+[ 0.669689 , 5 , 4 , 19 ],
+[ 0.672651 , 9 , 8 , 45 ],
+[ 0.673671 , 16 , 15 , 13 ],
+[ 0.673851 , 22 , 4 , 19 ],
+[ 0.677769 , 38 , 4 , 19 ],
+[ 0.679638 , 16 , 15 , 14 ],
+[ 0.681716 , 5 , 4 , 20 ],
+[ 0.684357 , 15 , 14 , 47 ],
+[ 0.684682 , 9 , 8 , 46 ],
+[ 0.685879 , 22 , 4 , 20 ],
+[ 0.689797 , 38 , 4 , 20 ],
+[ 0.693754 , 5 , 4 , 21 ],
+[ 0.697724 , 9 , 8 , 47 ],
+[ 0.697916 , 22 , 4 , 21 ],
+[ 0.698735 , 9 , 8 , 48 ],
+[ 0.701834 , 38 , 4 , 21 ],
+[ 0.704682 , 16 , 15 , 15 ],
+[ 0.706649 , 16 , 15 , 16 ],
+[ 0.709759 , 9 , 8 , 49 ],
+[ 0.720790 , 9 , 8 , 50 ],
+[ 0.722619 , 10 , 9 , 32 ],
+[ 0.722631 , 10 , 9 , 33 ],
+[ 0.722892 , 11 , 10 , 32 ],
+[ 0.722904 , 11 , 10 , 33 ],
+[ 0.726797 , 16 , 15 , 17 ],
+[ 0.727835 , 16 , 15 , 18 ],
+[ 0.729456 , 15 , 14 , 48 ],
+[ 0.729465 , 15 , 14 , 49 ],
+[ 0.729474 , 15 , 14 , 50 ],
+[ 0.731460 , 15 , 14 , 51 ],
+[ 0.732455 , 15 , 14 , 52 ],
+[ 0.739418 , 16 , 15 , 19 ],
+[ 0.746289 , 16 , 15 , 20 ],
+[ 0.751407 , 15 , 14 , 53 ],
+[ 0.753832 , 9 , 8 , 51 ],
+[ 0.758495 , 16 , 15 , 21 ],
+[ 0.765879 , 9 , 8 , 52 ],
+[ 0.766737 , 16 , 15 , 22 ],
+[ 0.771400 , 15 , 14 , 54 ],
+[ 0.777913 , 9 , 8 , 53 ],
+[ 0.781005 , 16 , 15 , 23 ],
+[ 0.789288 , 10 , 9 , 34 ],
+[ 0.789300 , 10 , 9 , 35 ],
+[ 0.789582 , 11 , 10 , 34 ],
+[ 0.789594 , 11 , 10 , 35 ],
+[ 0.792949 , 9 , 8 , 54 ],
+[ 0.802148 , 16 , 15 , 24 ],
+[ 0.803977 , 9 , 8 , 55 ],
+[ 0.816021 , 9 , 8 , 56 ],
+[ 0.817929 , 16 , 15 , 25 ],
+[ 0.821540 , 15 , 14 , 55 ],
+[ 0.825506 , 16 , 15 , 26 ],
+[ 0.831054 , 9 , 8 , 57 ],
+[ 0.831411 , 15 , 14 , 56 ],
+[ 0.839831 , 17 , 16 , 51 ],
+[ 0.840635 , 16 , 15 , 27 ],
+[ 0.842103 , 9 , 8 , 58 ],
+[ 0.851474 , 15 , 14 , 57 ],
+[ 0.852470 , 15 , 14 , 58 ],
+[ 0.853140 , 9 , 8 , 59 ],
+[ 0.853475 , 15 , 14 , 59 ],
+[ 0.853484 , 15 , 14 , 60 ],
+[ 0.855961 , 10 , 9 , 36 ],
+[ 0.855973 , 10 , 9 , 37 ],
+[ 0.856244 , 11 , 10 , 36 ],
+[ 0.856257 , 11 , 10 , 37 ],
+[ 0.864849 , 17 , 16 , 52 ],
+[ 0.865181 , 9 , 8 , 60 ],
+[ 0.873668 , 16 , 15 , 28 ],
+[ 0.877226 , 9 , 8 , 61 ],
+[ 0.879894 , 16 , 15 , 29 ],
+[ 0.883446 , 16 , 15 , 30 ],
+[ 0.890863 , 17 , 16 , 53 ],
+[ 0.893281 , 9 , 8 , 62 ],
+[ 0.904590 , 16 , 15 , 31 ],
+[ 0.904798 , 5 , 4 , 22 ],
+[ 0.905312 , 9 , 8 , 63 ],
+[ 0.905875 , 16 , 15 , 32 ],
+[ 0.908546 , 15 , 14 , 61 ],
+[ 0.908960 , 22 , 4 , 22 ],
+[ 0.912878 , 38 , 4 , 22 ],
+[ 0.913547 , 15 , 14 , 62 ],
+[ 0.915890 , 17 , 16 , 54 ],
+[ 0.916361 , 9 , 8 , 64 ],
+[ 0.921961 , 16 , 15 , 33 ],
+[ 0.922644 , 10 , 9 , 38 ],
+[ 0.922656 , 10 , 9 , 39 ],
+[ 0.922904 , 11 , 10 , 38 ],
+[ 0.922916 , 11 , 10 , 39 ],
+[ 0.934286 , 16 , 15 , 34 ],
+[ 0.940910 , 17 , 16 , 55 ],
+[ 0.942193 , 16 , 15 , 35 ],
+[ 0.944506 , 16 , 15 , 36 ],
+[ 0.965936 , 17 , 16 , 56 ],
+[ 0.969857 , 16 , 15 , 37 ],
+[ 0.975835 , 15 , 14 , 63 ],
+[ 0.975844 , 15 , 14 , 64 ],
+[ 0.975863 , 15 , 14 , 65 ],
+[ 0.975872 , 15 , 14 , 66 ],
+[ 0.976617 , 15 , 14 , 67 ],
+[ 0.982975 , 16 , 15 , 38 ],
+[ 0.985992 , 16 , 15 , 39 ],
+[ 0.986297 , 16 , 15 , 40 ],
+[ 0.989298 , 10 , 9 , 40 ],
+[ 0.989310 , 10 , 9 , 41 ],
+[ 0.989594 , 11 , 10 , 40 ],
+[ 0.989606 , 11 , 10 , 41 ],
+[ 0.990941 , 17 , 16 , 57 ],
+[ 0.995672 , 15 , 14 , 68 ],
+[ 0.999683 , 15 , 14 , 69 ],
+[ 1.002439 , 16 , 15 , 41 ],
+[ 1.015955 , 17 , 16 , 58 ],
+[ 1.024748 , 16 , 15 , 42 ],
+[ 1.041958 , 17 , 16 , 59 ],
+[ 1.044547 , 16 , 15 , 43 ],
+[ 1.050651 , 16 , 15 , 44 ],
+[ 1.050894 , 17 , 16 , 60 ],
+[ 1.055988 , 10 , 9 , 42 ],
+[ 1.056000 , 10 , 9 , 43 ],
+[ 1.056262 , 11 , 10 , 42 ],
+[ 1.056274 , 11 , 10 , 43 ],
+[ 1.065697 , 15 , 14 , 70 ],
+[ 1.065711 , 15 , 14 , 71 ],
+[ 1.066959 , 17 , 16 , 61 ],
+[ 1.075249 , 16 , 15 , 45 ],
+[ 1.091945 , 16 , 15 , 46 ],
+[ 1.091971 , 17 , 16 , 62 ],
+[ 1.108032 , 16 , 15 , 47 ],
+[ 1.116998 , 17 , 16 , 63 ],
+[ 1.117068 , 16 , 15 , 48 ],
+[ 1.122290 , 10 , 9 , 44 ],
+[ 1.122302 , 10 , 9 , 45 ],
+[ 1.122944 , 11 , 10 , 44 ],
+[ 1.122957 , 11 , 10 , 45 ],
+[ 1.127419 , 9 , 8 , 65 ],
+[ 1.129047 , 16 , 15 , 49 ],
+[ 1.129798 , 15 , 14 , 72 ],
+[ 1.129807 , 15 , 14 , 73 ],
+[ 1.129816 , 15 , 14 , 74 ],
+[ 1.130463 , 15 , 14 , 75 ],
+[ 1.130485 , 16 , 15 , 50 ],
+[ 1.132780 , 15 , 14 , 76 ],
+[ 1.142023 , 17 , 16 , 64 ],
+[ 1.143818 , 16 , 15 , 51 ],
+[ 1.146341 , 16 , 15 , 52 ],
+[ 1.152832 , 15 , 14 , 77 ],
+[ 1.157833 , 15 , 14 , 78 ],
+[ 1.161947 , 16 , 15 , 53 ],
+[ 1.162838 , 16 , 15 , 54 ],
+[ 1.167045 , 17 , 16 , 65 ],
+[ 1.181006 , 16 , 15 , 55 ],
+[ 1.189311 , 10 , 9 , 46 ],
+[ 1.189323 , 10 , 9 , 47 ],
+[ 1.189328 , 16 , 15 , 56 ],
+[ 1.189586 , 11 , 10 , 46 ],
+[ 1.189599 , 11 , 10 , 47 ],
+[ 1.190854 , 5 , 4 , 23 ],
+[ 1.193063 , 17 , 16 , 66 ],
+[ 1.195016 , 22 , 4 , 23 ],
+[ 1.198934 , 38 , 4 , 23 ],
+[ 1.199124 , 16 , 15 , 57 ],
+[ 1.202835 , 16 , 15 , 58 ],
+[ 1.202904 , 5 , 4 , 24 ],
+[ 1.207066 , 22 , 4 , 24 ],
+[ 1.210984 , 38 , 4 , 24 ],
+[ 1.213944 , 5 , 4 , 25 ],
+[ 1.218076 , 17 , 16 , 67 ],
+[ 1.218106 , 22 , 4 , 25 ],
+[ 1.218838 , 15 , 14 , 79 ],
+[ 1.222024 , 38 , 4 , 25 ],
+[ 1.222837 , 15 , 14 , 80 ],
+[ 1.224988 , 5 , 4 , 26 ],
+[ 1.225756 , 16 , 15 , 59 ],
+[ 1.229150 , 22 , 4 , 26 ],
+[ 1.233068 , 38 , 4 , 26 ],
+[ 1.233587 , 16 , 15 , 60 ],
+[ 1.237033 , 5 , 4 , 27 ],
+[ 1.240916 , 16 , 15 , 61 ],
+[ 1.241195 , 22 , 4 , 27 ],
+[ 1.243078 , 17 , 16 , 68 ],
+[ 1.245113 , 38 , 4 , 27 ],
+[ 1.245397 , 16 , 15 , 62 ],
+[ 1.248080 , 5 , 4 , 28 ],
+[ 1.250915 , 15 , 14 , 81 ],
+[ 1.250925 , 15 , 14 , 82 ],
+[ 1.250934 , 15 , 14 , 83 ],
+[ 1.251448 , 15 , 14 , 84 ],
+[ 1.252242 , 22 , 4 , 28 ],
+[ 1.253035 , 17 , 16 , 69 ],
+[ 1.253897 , 15 , 14 , 85 ],
+[ 1.255826 , 11 , 10 , 48 ],
+[ 1.255838 , 11 , 10 , 49 ],
+[ 1.255983 , 10 , 9 , 48 ],
+[ 1.255995 , 10 , 9 , 49 ],
+[ 1.256160 , 38 , 4 , 28 ],
+[ 1.259121 , 5 , 4 , 29 ],
+[ 1.263283 , 22 , 4 , 29 ],
+[ 1.264721 , 16 , 15 , 63 ],
+[ 1.267201 , 38 , 4 , 29 ],
+[ 1.268084 , 17 , 16 , 70 ],
+[ 1.268970 , 16 , 15 , 64 ],
+[ 1.270157 , 5 , 4 , 30 ],
+[ 1.274319 , 22 , 4 , 30 ],
+[ 1.278237 , 38 , 4 , 30 ],
+[ 1.280945 , 16 , 15 , 65 ],
+[ 1.282198 , 5 , 4 , 31 ],
+[ 1.286360 , 22 , 4 , 31 ],
+[ 1.288148 , 16 , 15 , 66 ],
+[ 1.290278 , 38 , 4 , 31 ],
+[ 1.293092 , 17 , 16 , 71 ],
+[ 1.293232 , 5 , 4 , 32 ],
+[ 1.297394 , 22 , 4 , 32 ],
+[ 1.301312 , 38 , 4 , 32 ],
+[ 1.303023 , 16 , 15 , 67 ],
+[ 1.304276 , 5 , 4 , 33 ],
+[ 1.307395 , 16 , 15 , 68 ],
+[ 1.308438 , 22 , 4 , 33 ],
+[ 1.309955 , 15 , 14 , 86 ],
+[ 1.309967 , 15 , 14 , 87 ],
+[ 1.312356 , 38 , 4 , 33 ],
+[ 1.316311 , 5 , 4 , 34 ],
+[ 1.318101 , 17 , 16 , 72 ],
+[ 1.320473 , 22 , 4 , 34 ],
+[ 1.322583 , 11 , 10 , 50 ],
+[ 1.322589 , 11 , 10 , 51 ],
+[ 1.322601 , 11 , 10 , 52 ],
+[ 1.322669 , 10 , 9 , 50 ],
+[ 1.322681 , 10 , 9 , 51 ],
+[ 1.324145 , 16 , 15 , 69 ],
+[ 1.324391 , 38 , 4 , 34 ],
+[ 1.325865 , 16 , 15 , 70 ],
+[ 1.327344 , 5 , 4 , 35 ],
+[ 1.331507 , 22 , 4 , 35 ],
+[ 1.335425 , 38 , 4 , 35 ],
+[ 1.338373 , 5 , 4 , 36 ],
+[ 1.342536 , 22 , 4 , 36 ],
+[ 1.344101 , 17 , 16 , 73 ],
+[ 1.344808 , 16 , 15 , 71 ],
+[ 1.346454 , 38 , 4 , 36 ],
+[ 1.350858 , 16 , 15 , 72 ],
+[ 1.366744 , 16 , 15 , 73 ],
+[ 1.369122 , 17 , 16 , 74 ],
+];
+
+sfr_names=["http_get",
+ "http_post",
+ "https",
+ "http_browsing",
+ "exchange",
+ "mail_pop",
+ "mail_pop_1",
+ "mail_pop_2",
+ "oracle_0",
+ "rtp_160k",
+ "rtp_250k",
+ "smtp_0",
+ "smtp_1",
+ "smtp_2",
+ "video_call",
+ "sip_video_call_full",
+ "citrix_0",
+ "dns_0"];
+
+chart("#chart4",sfr_data,sfr_names,"time-sec","flow-id");
+</script>
++++++++++++++++++++++++++++++++++
+endif::backend-docbook[]
+
+
+=== Running examples
+
+TRex commands typically include the following main arguments, but only `-f` is required.
+
+[source,bash]
+----
+$.sudo /t-rex-64 -f <traffic_yaml> -m <multiplier> -d <duration> -l <latency test rate> -c <cores>
+----
+Full command line reference can be found xref:cml-line[here]
+
+==== TRex command line examples
+
+.Simple HTTP 1Gb/sec for 100 sec
+[source,bash]
+----
+$.sudo /t-rex-64 -f cap2/simple_http.yaml -c 4 -m 100 -d 100
+----
+
+.Simple HTTP 1Gb/sec with latency for 100 sec
+[source,bash]
+----
+$.sudo /t-rex-64 -f cap2/simple_http.yaml -c 4 -m 100 -d 100 -l 1000
+----
+
+.SFR 35Gb/sec traffic
+[source,bash]
+----
+$.sudo /t-rex-64 -f avl/sfr_delay_10_1g.yaml -c 4 -m 35 -d 100 -p
+----
+
+.SFR 20Gb/sec traffic with latency
+[source,bash]
+----
+$.sudo /t-rex-64 -f avl/sfr_delay_10_1g.yaml -c 4 -m 20 -d 100 -l 1000
+----
+
+.SFR ipv6 20Gb/sec traffic with latency
+[source,bash]
+----
+$.sudo /t-rex-64 -f avl/sfr_delay_10_1g_no_bundeling.yaml -c 4 -m 20 -d 100 -l 1000 --ipv6
+----
+
+.Simple HTTP 1Gb/sec with NAT translation support
+[source,bash]
+----
+$.sudo /t-rex-64 -f cap2/simple_http.yaml -c 4 -m 100 -d 100 -l 1000 --learn-mode 1
+----
+
+.IMIX 1G/sec ,1600 flows
+[source,bash]
+----
+$.sudo /t-rex-64 -f cap2/imix_fast_1g.yaml -c 4 -m 1 -d 100 -l 1000
+----
+
+.IMIX 1Gb/sec,100K flows
+[source,bash]
+----
+$.sudo /t-rex-64 -f cap2/imix_fast_1g_100k.yaml -c 4 -m 1 -d 100 -l 1000
+----
+
+.64bytes ~1Gb/sec,1600 flows
+[source,bash]
+----
+$.sudo /t-rex-64 -f cap2/imix_64.yaml -c 4 -m 1 -d 100 -l 1000
+----
+
+=== Traffic profiles provided with the TRex package
+
+
+[options="header",cols="1,3",width="100%"]
+|=================
+| name | description
+| cap2/dns.yaml | simple dns pcap file
+| cap2/http_simple.yaml | simple http cap file
+| avl/sfr_delay_10_1g_no_bundeling.yaml | sfr traffic profile capture from Avalanche - Spirent without bundeling support with RTT=10msec ( a delay machine), this can be used with --ipv6 and --learn-mode
+| avl/sfr_delay_10_1g.yaml | head-end sfr traffic profile capture from Avalanche - Spirent with bundeling support with RTT=10msec ( a delay machine), it is normalized to 1Gb/sec for m=1
+| avl/sfr_branch_profile_delay_10.yaml | branch sfr profile capture from Avalanche - Spirent with bundeling support with RTT=10msec it, is normalized to 1Gb/sec for m=1
+| cap2/imix_fast_1g.yaml | imix profile with 1600 flows normalized to 1Gb/sec.
+| cap2/imix_fast_1g_100k_flows.yaml | imix profile with 100k flows normalized to 1Gb/sec.
+| cap2/imix_64.yaml | 64byte UDP packets profile
+|========================
+
+
+=== Mimicking stateless traffic under stateful mode
+[NOTE]
+TRex supports also true stateless traffic generation.
+If you are looking for stateless traffic, please visit the following link: xref:trex_stateless.html[TRex Stateless Support]
+
+With this feature you can "repeat" flows and create stateless, *IXIA* like streams.
+After injecting the number of flows defined by `limit`, TRex repeats the same flows. If all templates have `limit` the CPS will be zero after some time as there are no new flows after the first iteration.
+
+*IMIX support:*::
+Example:
+[source,bash]
+----
+$sudo ./t-rex-64 -f cap2/imix_64.yaml -d 1000 -m 40000 -c 4 -p
+----
+
+[WARNING]
+=====================================================================
+The *-p* is used here to send the client side packets from both interfaces.
+(Normally it is sent from client ports only.)
+With this option, the port is selected by the client IP.
+All the packets of a flow are sent from the same interface. This may create an issue with routing, as the client's IP will be sent from the server interface. PBR router configuration solves this issue but cannot be used in all cases. So use this `-p` option carefully.
+=====================================================================
+
+
+.imix_64.yaml
+[source,python]
+----
+ cap_info :
+ - name: cap2/udp_64B.pcap
+ cps : 1000.0
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 1000 <1>
+----
+<1> Repeats the flows in a loop, generating 1000 flows from this type. In this example, udp_64B includes only one packet.
+
+The cap file "cap2/udp_64B.pcap" includes only one packet of 64B. This configuration file creates 1000 flows that will be repeated as follows:
+f1 , f2 , f3 .... f1000 , f1 , f2 ...
+where the PPS == CPS for -m=1. In this case it will have PPS=1000 in sec for -m==1.
+It is possible to mix stateless templates and stateful templates.
+
+.Imix YAML `cap2/imix_fast_1g.yaml` example
+[source,python]
+----
+- duration : 3
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.255.255"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 0
+ udp_aging : 0
+ mac : [0x0,0x0,0x0,0x1,0x0,0x00]
+ cap_info :
+ - name: cap2/udp_64B.pcap
+ cps : 90615
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 199
+ - name: cap2/udp_576B.pcap
+ cps : 64725
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 199
+ - name: cap2/udp_1500B.pcap
+ cps : 12945
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 199
+ - name: cap2/udp_64B.pcap
+ cps : 90615
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 199
+ - name: cap2/udp_576B.pcap
+ cps : 64725
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 199
+ - name: cap2/udp_1500B.pcap
+ cps : 12945
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 199
+----
+The templates are duplicated here to better utilize DRAM and to get better performance.
+//TBD: What exactly repeates the templates - TRex, script, ? Also, how does that better utilize DRAM.
+
+.Imix YAML `cap2/imix_fast_1g_100k_flows.yaml` example
+[source,python]
+----
+- duration : 3
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.255.255"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 0
+ udp_aging : 0
+ mac : [0x0,0x0,0x0,0x1,0x0,0x00]
+ cap_info :
+ - name: cap2/udp_64B.pcap
+ cps : 90615
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 16666
+ - name: cap2/udp_576B.pcap
+ cps : 64725
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 16666
+ - name: cap2/udp_1500B.pcap
+ cps : 12945
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 16667
+ - name: cap2/udp_64B.pcap
+ cps : 90615
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 16667
+ - name: cap2/udp_576B.pcap
+ cps : 64725
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 16667
+ - name: cap2/udp_1500B.pcap
+ cps : 12945
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 16667
+----
+
+The following example of a simple simulation includes 3 flows, with CPS=10.
+
+[source,python]
+----
+$more cap2/imix_example.yaml
+#
+# Simple IMIX test (7x64B, 5x576B, 1x1500B)
+#
+- duration : 3
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.255.255"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 0
+ udp_aging : 0
+ mac : [0x0,0x0,0x0,0x1,0x0,0x00]
+ cap_info :
+ - name: cap2/udp_64B.pcap
+ cps : 10.0
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ limit : 3 <1>
+
+----
+<1> Number of flows: 3
+
+
+[source,bash]
+----
+./bp-sim-32-debug -f cap2/imix_example.yaml -o my.erf -v 3 > a.txt
+----
+
+.IMIX example limit=3
+[format="csv",cols="1^,2^,1^,1^,1^,2^,1^,2^,1^", options="header"]
+|=================
+pkt,time sec,template,fid,flow-pkt-id,client_ip,client_port,server_ip ,desc
+ 1 , 0.010000 , 0 , 1 , 1 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 2 , 0.210000 , 0 , 2 , 0 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 3 , 0.310000 , 0 , 3 , 0 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 4 , 0.310000 , 0 , 1 , 0 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 5 , 0.510000 , 0 , 2 , 0 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 6 , 0.610000 , 0 , 3 , 0 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 7 , 0.610000 , 0 , 1 , 0 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 8 , 0.810000 , 0 , 2 , 0 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 9 , 0.910000 , 0 , 1 , 0 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 10 , 0.910000 , 0 , 3 , 0 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 11 , 1.110000 , 0 , 2 , 0 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 12 , 1.210000 , 0 , 3 , 0 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 13 , 1.210000 , 0 , 1 , 0 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 14 , 1.410000 , 0 , 2 , 0 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 15 , 1.510000 , 0 , 1 , 0 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 16 , 1.510000 , 0 , 3 , 0 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 17 , 1.710000 , 0 , 2 , 0 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 18 , 1.810000 , 0 , 3 , 0 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 19 , 1.810000 , 0 , 1 , 0 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 20 , 2.010000 , 0 , 2 , 0 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 21 , 2.110000 , 0 , 1 , 0 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 22 , 2.110000 , 0 , 3 , 0 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 23 , 2.310000 , 0 , 2 , 0 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 24 , 2.410000 , 0 , 3 , 0 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 25 , 2.410000 , 0 , 1 , 0 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 26 , 2.610000 , 0 , 2 , 0 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 27 , 2.710000 , 0 , 1 , 0 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 28 , 2.710000 , 0 , 3 , 0 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 29 , 2.910000 , 0 , 2 , 0 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 30 , 3.010000 , 0 , 3 , 0 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 31 , 3.010000 , 0 , 1 , 0 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+|=================
+
+* Average CPS: 10 packets per second (30 packets in 3 sec).
+* Total of 3 flows, as specified in the configuration file.
+* The flows come in bursts, as specified in the configuration file.
+
+
+ifndef::backend-docbook[]
++++++++++++++++++++++++++++++++++
+<div id="chart_imix" style="font : 10px sans-serif"; ></div>
+
+<script>
+var imix_data=[
+[ 0.010000 , 1 , 0 , 1 ],
+[ 0.210000 , 2 , 0 , 0 ],
+[ 0.310000 , 3 , 0 , 0 ],
+[ 0.310000 , 1 , 0 , 0 ],
+[ 0.510000 , 2 , 0 , 0 ],
+[ 0.610000 , 3 , 0 , 0 ],
+[ 0.610000 , 1 , 0 , 0 ],
+[ 0.810000 , 2 , 0 , 0 ],
+[ 0.910000 , 1 , 0 , 0 ],
+[ 0.910000 , 3 , 0 , 0 ],
+[ 1.110000 , 2 , 0 , 0 ],
+[ 1.210000 , 3 , 0 , 0 ],
+[ 1.210000 , 1 , 0 , 0 ],
+[ 1.410000 , 2 , 0 , 0 ],
+[ 1.510000 , 1 , 0 , 0 ],
+[ 1.510000 , 3 , 0 , 0 ],
+[ 1.710000 , 2 , 0 , 0 ],
+[ 1.810000 , 3 , 0 , 0 ],
+[ 1.810000 , 1 , 0 , 0 ],
+[ 2.010000 , 2 , 0 , 0 ],
+[ 2.110000 , 1 , 0 , 0 ],
+[ 2.110000 , 3 , 0 , 0 ],
+[ 2.310000 , 2 , 0 , 0 ],
+[ 2.410000 , 3 , 0 , 0 ],
+[ 2.410000 , 1 , 0 , 0 ],
+[ 2.610000 , 2 , 0 , 0 ],
+[ 2.710000 , 1 , 0 , 0 ],
+[ 2.710000 , 3 , 0 , 0 ],
+[ 2.910000 , 2 , 0 , 0 ],
+[ 3.010000 , 3 , 0 , 0 ],
+[ 3.010000 , 1 , 0 , 0 ],
+];
+
+chart("#chart_imix",imix_data,["udp_64"],"time-sec","flow-id");
+</script>
++++++++++++++++++++++++++++++++++
+endif::backend-docbook[]
+
+=== Clients/Servers IP allocation scheme
+
+Currently, there is one global IP pool for clients and servers. It serves all templates. All templates will allocate IP from this global pool.
+Each TRex client/server "dual-port" (pair of ports, such as port 0 for client, port 1 for server) has its own generator offset, taken from the config file. The offset is called `dual_port_mask`.
+
+Example:
+
+[source,python]
+----
+generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.0.255"
+ dual_port_mask : "1.0.0.0" <1>
+ tcp_aging : 0
+ udp_aging : 0
+----
+<1> Offset to add per port pair.
+The reason for the ``dual_port_mask'' is to make static route configuration per port possible. With this offset, different ports have different prefixes.
+
+For example, with four ports, TRex will produce the following ip ranges:
+
+[source,python]
+----
+ port pair-0 (0,1) --> C (16.0.0.1-16.0.0.128 ) <-> S( 48.0.0.1 - 48.0.0.128)
+ port pair-1 (2,3) --> C (17.0.0.129-17.0.0.255 ) <-> S( 49.0.0.129 - 49.0.0.255) + mask ("1.0.0.0")
+----
+
+- Number of clients : 255
+- Number of servers : 255
+- The offset defined by ``dual_port_mask'' (1.0.0.0) is added for each port pair, but the total number of clients/servers will remain constant (255), and will not depend on the amount of ports.
+- TCP/UDP aging is the time it takes to return the socket to the pool. It is required when the number of clients is very small and the template defines a very long duration.
+//TBD: not clear - is TCP/UDP aging an option used when the template defines a long duration? also, should specify what "very long" refers to.
+
+If ``dual-port_mask'' was set to 0.0.0.0, both port pairs would have uses the same ip range.
+For example, with four ports, we would have get the following ip range is :
+
+[source,python]
+----
+ port pair-0 (0,1) --> C (16.0.0.1-16.0.0.128 ) <-> S( 48.0.0.1 - 48.0.0.128)
+ port pair-1 (2,3) --> C (16.0.0.129-16.0.0.255 ) <-> S( 48.0.0.129 - 48.0.0.255)
+----
+
+
+*Router configuration for this mode:*::
+
+PBR is not necessary. The following configuration is sufficient.
+//TBD: clarify
+
+[source,python]
+----
+interface TenGigabitEthernet1/0/0 <1>
+ mac-address 0000.0001.0000
+ mtu 4000
+ ip address 11.11.11.11 255.255.255.0
+!
+`
+interface TenGigabitEthernet1/1/0 <2>
+ mac-address 0000.0001.0000
+ mtu 4000
+ ip address 22.11.11.11 255.255.255.0
+!
+interface TenGigabitEthernet1/2/0 <3>
+ mac-address 0000.0001.0000
+ mtu 4000
+ ip address 33.11.11.11 255.255.255.0
+!
+interface TenGigabitEthernet1/3/0 <4>
+ mac-address 0000.0001.0000
+ mtu 4000
+ ip address 44.11.11.11 255.255.255.0
+ load-interval 30
+
+
+ip route 16.0.0.0 255.0.0.0 22.11.11.12
+ip route 48.0.0.0 255.0.0.0 11.11.11.12
+ip route 17.0.0.0 255.0.0.0 44.11.11.12
+ip route 49.0.0.0 255.0.0.0 33.11.11.12
+----
+<1> Connected to TRex port 0 (client side)
+<2> Connected to TRex port 1 (server side)
+<3> Connected to TRex port 2 (client side)
+<4> Connected to TRex port 3(server side)
+
+*One server:*::
+
+To support a template with one server, you can add ``server_addr'' keyword. Each port pair will be get different server IP
+(According to the ``dual_port_mask'' offset).
+
+[source,python]
+----
+- name: cap2/dns.pcap
+ cps : 1.0
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ server_addr : "48.0.0.1" <1>
+ one_app_server : true <2>
+ wlength : 1
+----
+<1> Server IP.
+<2> Enable one server mode.
+
+// TBD - what is wlength???
+
+In TRex server, you will see the following statistics.
+// TBD - need to explain this
+
+[source,python]
+----
+ Active-flows : 19509 Clients : 504 Socket-util : 0.0670 %
+ Open-flows : 247395 Servers : 65408 Socket : 21277 Socket/Clients : 42.2
+----
+
+
+[NOTE]
+=====================================================================
+* No backward compatibility with the old generator YAML format.
+* When using -p option, TRex will not comply with the static route rules. Server-side traffic may be sent from the client side (port 0) and vice-versa.
+If you use the -p option, you must configure policy based routing to pass all traffic from router port 1 to router port 2, and vice versa.
+* xref:trex_vlan[VLAN] feature does not comply with static route rules. If you use it, you also need policy based routing
+rules to pass packets from VLAN0 to VLAN1 and vice versa.
+* Limitation: When using template with plugins (bundles), the number of servers must be higher than the number of clients.
+=====================================================================
+
+==== More Details about IP allocations
+
+Each time a new flow is created, TRex allocates new Client IP/port and Server IP. This 3-tuple should be distinct among active flows.
+
+Currently, only sequential distribution is supported in IP allocation. This means the IP address is increased by one for each flow.
+
+For example, if we have a pool of two IP addresses: 16.0.0.1 and 16.0.0.2, the allocation of client src/port pairs will be
+
+[source,python]
+----
+16.0.0.0.1 [1024]
+16.0.0.0.2 [1024]
+16.0.0.0.1 [1025]
+16.0.0.0.2 [1025]
+16.0.0.0.1 [1026]
+16.0.0.0.2 [1026]
+...
+----
+
+==== How to determine the packet per second(PPS) and Bit per second (BPS)
+
+- Let's look at an example of one flow with 4 packets.
+- Green circles represent the first packet of each flow.
+- The client ip pool starts from 16.0.0.1, and the distribution is seq.
+
+image:images/ip_allocation.png[title=""]
+
+latexmath:[$Total PPS = \sum_{k=0}^{n}(CPS_{k}\times {flow\_pkts}_{k})$]
+
+latexmath:[$Concurrent flow = \sum_{k=0}^{n}CPS_{k}\times flow\_duration_k $]
+// TBD Ido: The latexmath formulas only looks good in pdf format. In HTML they are not clear.
+
+The above formulas can be used to calculate the PPS. The TRex throughput depends on the PPS calculated above and the value of m (a multiplier given as command line argument -m).
+
+The m value is a multiplier of total pcap files CPS.
+CPS of pcap file is configured on yaml file.
+
+Let's take a simple example as below.
+
+
+[source,python]
+----
+cap_info :
+ - name: avl/first.pcap < -- has 2 packets
+ cps : 102.0
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/second.pcap < -- has 20 packets
+ cps : 50.0
+ ipg : 10000
+ rtt : 10000
+ w : 1
+----
+
+The throughput is: 'm*(CPS_1*flow_pkts+CPS_2*flow_pkts)'
+
+So if the m is set as 1, the total PPS is : 102*2+50*20 = 1204 PPS.
+
+The BPS depends on the packet size. You can refer to your packet size and get the BPS = PPS*Packet_size.
+
+==== Per template allocation + future plans
+
+- *1) per-template generator*
+
+Multiple generators can be defined and assigned to different pcap file templates.
+
+The YAML configuration is something like this:
+
+
+[source,python]
+----
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.1.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.20.255"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 0
+ udp_aging : 0
+ generator_clients :
+ - name : "c1"
+ distribution : "random"
+ ip_start : "38.0.0.1"
+ ip_end : "38.0.1.255"
+ clients_per_gb : 201
+ min_clients : 101
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 0
+ udp_aging : 0
+ generator_servers :
+ - name : "s1"
+ distribution : "seq"
+ ip_start : "58.0.0.1"
+ ip_end : "58.0.1.255"
+ dual_port_mask : "1.0.0.0"
+ cap_info :
+ - name: avl/delay_10_http_get_0.pcap
+ cps : 404.52
+ ipg : 10000
+ rtt : 10000
+ w : 1
+ - name: avl/delay_10_http_post_0.pcap
+ client_pool : "c1"
+ server_pool : "s1"
+ cps : 404.52
+ ipg : 10000
+ rtt : 10000
+ w : 1
+----
+
+- *2) More distributions will be supported in the future (normal distribution for example)*
+
+Currently, only sequcence and random are supported.
+
+- *3) Histogram of tuple pool will be supported*
+
+This feature will give the user more flexibility in defining the IP generator.
+
+[source,python]
+----
+ generator :
+ client_pools:
+ - name : "a"
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.1.255"
+ tcp_aging : 0
+ udp_aging : 0
+
+ - name : "b"
+ distribution : "random"
+ clients_start : 26.0.0.1"
+ clients_end : 26.0.1.255"
+ tcp_aging : 0
+ udp_aging : 0
+
+ - name : "c"
+ pools_list :
+ - name:"a"
+ probability: 0.8
+ - name:"b"
+ probability: 0.2
+----
+
+
+
+=== Measuring Jitter/Latency
+
+To measure jitter/latency using independent flows (SCTP or ICMP), use `-l [Hz]` where Hz defines the number of packets to send from each port per second.
+This option measures latency and jitter. We can define the type of traffic used for the latency measurement using the `--l-pkt-mode` option.
+
+
+[options="header",cols="^1,10a"]
+|=================
+| Option ID| Type
+| 0 |
+*default*, SCTP packets
+| 1 |
+ICMP echo request packets from both sides
+| 2 |
+Send ICMP requests from one side, and matching ICMP responses from other side.
+
+This is particulary usefull if your DUT drops traffic from outside, and you need to open pin hole to get the outside traffic in (for example when testing a firewall)
+
+| 3 |
+Send ICMP request packets with a constant 0 sequence number from both sides.
+|=================
+
+
+The shell output is similar to the following:
+
+[source,python]
+----
+ Cpu Utilization : 0.1 %
+ if| tx_ok , rx_ok , rx ,error, average , max , Jitter<1> ,max
+ | , , check, , latency(usec),latency (usec) ,(usec) , window
+ --------------------------------------------------------------------------------------
+ 0 | 1002, 1002, 2501, 0, 61 , 70, 3 | 60 60
+ 1 | 1002, 1002, 2012, 0, 56 , 63, 2 | 50 51
+ 2 | 1002, 1002, 2322, 0, 66 , 74, 5 | 68 59
+ 3 | 1002, 1002, 1727, 0, 58 , 68, 2 | 52 49
+
+ Rx Check stats enabled
+ ---------------------------------------------------------------------------------------
+ rx check: avg/max/jitter latency, 94 , 744, 49<1> | 252 287 3
+
+ active flows: 10, fif: 308, drop: 0, errors: 0
+ ---------------------------------------------------------------------------------------
+----
+<1> Jitter information
+
+
diff --git a/doc/trex_config.asciidoc b/doc/trex_config.asciidoc
new file mode 100755
index 00000000..742b9968
--- /dev/null
+++ b/doc/trex_config.asciidoc
@@ -0,0 +1,327 @@
+TRex first time configuration
+=============================
+:author: hhaim with the Help of Amir Kroparo. New rev fixes by Ido Barnea.
+:email: <hhaim@cisco.com>
+:description: TRex Getting started - instalation guide
+:revdate: 2014-11-01
+:revnumber: 0.2
+:deckjs_theme: swiss
+:deckjs_transition: horizontal-slide
+:scrollable:
+
+include::trex_ga.asciidoc[]
+
+
+++++++++++++++++++
+<script type="text/javascript"
+ src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
+</script>
+
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+
+<script src="my_chart.js"></script>
+
+<style>
+.axis path,
+.axis line {
+ fill: none;
+ stroke: #000;
+ shape-rendering: crispEdges;
+}
+
+.dot {
+ stroke: #000;
+}
+</style>
+
+
+<style type="text/css">
+
+h1 {
+ font-size: 2.5em;
+}
+
+h2 {
+ font-size: 1.5em;
+ color: #CD7300;
+ border-bottom-color: #000;
+}
+
+h7 {
+ font-size: 4.5em;
+ color: #CD7300;
+ position: relative;
+ top: auto;
+ text-align: center;
+ padding: 0;
+ -webkit-transform: none;
+ -moz-transform: none;
+ -ms-transform: none;
+ -o-transform: none;
+ transform: none;
+ padding: 0 48px;
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 50%;
+}
+
+h8 {
+ font-size: 2.25em;
+ font-weight: bold;
+ padding-top: .5em;
+ margin: 0 0 .66666em 0;
+ border-top: 3px solid #888;
+ color: #c00;
+ border-top-color: #ccc;
+ left: 0;
+ right: 0;
+ top: 40%;
+}
+
+
+html, body {
+ height: 100%;
+ margin: 0 auto;
+ max-width: 1000px;
+}
+
+</style>
+
+<script>
+ $('#title-slide').css("background-image", "url('images/trex_logo.png')");
+ $('#title-slide').css("background-repeat","no-repeat");
+ $('#title-slide').css("background-position","center");
+ $('h1').html('');
+ $('h3').html('<font size="4">Hanoch Haim </font>');
+ $('h4').html('<font size="4">Updated 10/2016</font>');
+ </script>
+
+++++++++++++++++++
+
+== General info
+* This guide will help you configure Cisco ASR1K as DUT connected to TRex running in stateful mode.
+* This can be easily adopted for working with any L3 device. Equivalent commands for configuring Linux as your DUT are shown at the end as well.
+* Two options are given for configuring the router. Policy based route, and static route. You should
+choose the one appropriate for your needs.
+* TRex should be directly connected to ASR1K ports, and will act as both client and server.
+
+== Setup description
+
+* TRex will emulate the networks described in the figure below (on each side of the DUT, router connected to one or more clients/servers networks).
+
+image::images/trex-asr-setup.png[title="TRex/Router setup"]
+
+== Not supported setup description
+
+* Notice that the following setup is *not* supported (Having TRex emulate a bunch of hosts connected by switch to the DUT).
+This means that the TRex IP addresses defined in ``generator'' section should be in different network then the DUT addresses
+and TRex addresses defined in port_info section.
+
+image::images/trex-not-supported-setup.png[title="Not supported setup"]
+
+== TRex configuration
+
+* You can specify config file to use by the `--cfg` command line argument
+or use the default config file `/etc/trex_cfg.yaml`
+* Below is an example of how to configure TRex IP addresses. TRex will issue ARP for default_gw,
+and send gratuitous ARP for ip, on each port. This works, starting from TRex version 2.10.
+If you want to configure MAC addresses manually (equivalent to static
+ARP), or running older TRex version, information is available at the end of the presentation.
+Full description of config file parameters can be found in the manual.
+
+
+[source,python]
+----
+ - port_limit : 2
+ port_info :
+ - default_gw : 11.11.11.1 #<1>
+ ip : 11.11.11.2 #<2>
+ - default_gw : 12.12.12.1 #<3>
+ ip : 12.12.12.2 #<4>
+----
+<1> TRex port 0 config- should be router's TenG 0/0/0 IP. TRex will try to resolve this address by sending ARP request.
+<2> Next hop of router's TenG 0/0/0. TRex will send gratuitous ARP for this address.
+<3> TRex port 1 config- should be router's TenG 0/0/1 IP. TRex will try to resolve this address by sending ARP request.
+<4> Next hop of router's TenG 0/0/0. TRex will send gratuitous ARP for this address.
+
+== TRex emulated server/client IPs definition in traffic config file
+
+* You specify traffic config file by running TRex with -f <file name> (TRex stateful mode).
+* Examples for client config files exist in TREX_ROOT/scripts/cfg directory.
+* Add following section to the traffic config file, to define the range of IPs for clients and servers.
+
+[source,python]
+----
+generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.0.240"
+----
+
+* In this example, there are:
+** 255 clients talking to 240 servers
+
+== Router config. Option 1 - static routes
+
+[source,python]
+----
+interface TenGigabitEthernet0/0/0
+ ip address 11.11.11.1 255.255.255.0
+!
+`
+interface TenGigabitEthernet0/0/1
+ ip address 12.12.12.1 255.255.255.0
+!
+ip route 16.0.0.0 255.0.0.0 11.11.11.2 <1>
+ip route 48.0.0.0 255.0.0.0 12.12.12.2 <2>
+----
+<1> Route clients network to TRex server emulation interface.
+<2> Route servers network to TRex client emulation interface.
+
+== Router config. Option 2 - PBR part 1
+
+* Router is configured to statically route packets from 0/0/0 to 0/0/1 and from 0/0/1 to 0/0/0.
+
+*Router configuration:*::
+
+[source,python]
+----
+interface TenGigabitEthernet0/0/0
+ ip address 11.11.11.1 255.255.255.0 <1>
+ ip policy route-map p1_to_p2 <2>
+ load-interval 30
+!
+
+interface TenGigabitEthernet0/0/1
+ ip address 12.12.12.1 255.255.255.0 <1>
+ ip policy route-map p2_to_p1 <2>
+ load-interval 30
+!
+----
+<1> Configure ip address for the port.
+<2> Configure PBR policy - see next slide
+
+== Router config. Option 2 - PBR part 2
+
+[source,python]
+----
+
+route-map p1_to_p2 permit 10
+ set ip next-hop 12.12.12.2 <1>
+!
+route-map p2_to_p1 permit 10
+ set ip next-hop 11.11.11.2 <2>
+
+----
+
+<1> Set the destination to be 12.12.12.2, in the subnet of TenG 0/0/1.
+<2> Set the destination to be 11.11.11.2 , in the subnet to TenG 0/0/0.
+
+== Verify cable connections
+
+* To verify that TRex port-0 is really connected to Router 0/0/0, you can run the following.
+
+...........................................
+$./t-rex-64 -f cap2/dns.yaml -m 1 -d 10 -l 1000 --lo --lm 1
+...........................................
+* It sends packets only from TRex port-0 ( `--lm 1` )
+
+
+* to send only from TRex port 1 do this:
+...........................................
+$./t-rex-64 -f cap2/dns.yaml -m 1 -d 10 -l 1000 --lo --lm 2
+...........................................
+
+* If you are connected to a switch, you must send packets from both directions for few seconds first, to allow
+the switch to learn the MAC addresses of both sides.
+
+...........................................
+$./t-rex-64 -f cap2/dns.yaml -m 1 -d 10 -l 1000
+...........................................
+
+== MAC based configuration
+
+* If you use TRex version older than 2.10, or wish to have MAC based configuration, TRex config
+file must contain the following (instead of the ``ip'' and ``default_gw'').
+[source,python]
+----
+ - port_limit : 2
+ port_info : # set eh mac addr
+ - dest_mac : [0x0,0x0,0x0,0x1,0x0,0x0]
+ src_mac : [0x0,0x0,0x0,0x2,0x0,0x0]
+ - dest_mac : [0x0,0x0,0x0,0x3,0x0,0x0]
+ src_mac : [0x0,0x0,0x0,0x4,0x0,0x0]
+----
+=============================================================================
+. Should be Router's TenG 0/0/0 mac-address.
+. Router should be configured to send to this mac-address.
+. Should be Router's TenG 0/0/1 mac-address.
+. Router should be configured to send to this mac-address.
+=============================================================================
+
+* On the router side, you must add the following static ARP configuration.
+
+[source,python]
+----
+ arp 12.12.12.2 0000.0002.0000 ARPA #<1>
+ arp 11.11.11.2 0000.0004.0000 ARPA #<2>
+----
+<1> TRex port 0 source mac-address.
+<2> TRex port 1 source mac-address.
+
+== Linux config
+
+* Assuming the same setup with Linux as DUT instead of the router, you can do the following.
+* Configure IPs of Linux interfaces to 12.12.12.1 and 11.11.11.1
+[source,python]
+----
+route add -net 48.0.0.0 netmask 255.0.0.0 gw 12.12.12.2
+route add -net 16.0.0.0 netmask 255.0.0.0 gw 11.11.11.2
+----
+* If you have MAC based TRex config, you should also add:
+[source,python]
+----
+arp -s 12.12.12.2 00:00:00:04:00:00
+arp -s 11.11.11.2 00:00:00:04:00:00
+----
+
+== Static route configuration - IPV6
+
+[source,python]
+----
+interface TenGigabitEthernet1/0/0
+ ip address 11.11.11.1 255.255.255.0
+ ip policy route-map p1_to_p2
+ load-interval 30
+ ipv6 enable #<1>
+ ipv6 address 2001:DB8:1111:2222::1/64 #<2>
+ ipv6 policy route-map ipv6_p1_to_p2 #<3>
+!
+
+
+ipv6 unicast-routing #<4>
+
+ipv6 neighbor 3001::2 TenGigabitEthernet0/1/0 0000.0002.0002 #<5>
+ipv6 neighbor 2001::2 TenGigabitEthernet0/0/0 0000.0003.0002
+
+route-map ipv6_p1_to_p2 permit 10 #<6>
+ set ipv6 next-hop 2001::2
+!
+route-map ipv6_p2_to_p1 permit 10
+ set ipv6 next-hop 3001::2
+!
+
+
+csi-mcp-asr1k-40(config)#ipv6 route 4000::/64 2001::2
+csi-mcp-asr1k-40(config)#ipv6 route 5000::/64 3001::2
+----
+<1> Enable ipv6
+<2> Add ipv6 address
+<3> Add pbr
+<4> Enable ipv6 routing
+<5> Mac-addr setting should be like TRex
+<6> PBR configuraion
+
diff --git a/doc/trex_console.asciidoc b/doc/trex_console.asciidoc
new file mode 100755
index 00000000..f6928399
--- /dev/null
+++ b/doc/trex_console.asciidoc
@@ -0,0 +1,596 @@
+TRex console - commands proposal
+=================================
+:author: Hanoch Haim
+:email: <hhaim@cisco.com>
+:revnumber: 0.1
+:quotes.++:
+:numbered:
+:web_server_url: http://trex-tgn.cisco.com/trex
+:local_web_server_url: csi-wiki-01:8181/trex
+:toclevels: 4
+
+include::trex_ga.asciidoc[]
+
+== Console
+
+=== Overview
+
+The console will use TRex Client API for controling TRex
+Some guidelines:
+
+* Console should not save it own state, it should only cache server state. It assumed there is only one console that has R/W capability so once connected as R/W console (per user/port) it could read the server state and then cache all the operations.
+* There could be many read-only clients for same user same ports. The ability to enforce it does not yet exits in the server (will be done).
+* Console should sync with server to get the state in connection time and cache the server information locally once the state was changed
+* In case of crash/exit of the Console it should sync again at startup
+* Let's assume Console acquire all ports - for simplicity, for now.
+* Commands will be like bash shell - no order args, many flags
+* Ability to show stats in real time. gives the option to open two Console one for stats and one for commands ( many readonly clients)
+
+=== Ports State
+
+[options="header",cols="^1,3a"]
+|=================
+| state | meaning
+| IDLE | no streams, does not work
+| STREAMS | with streams, does not work
+| WORK | with streams, works
+| PAUSE | with streams, pause
+|=================
+
+
+[source,bash]
+----
+
+ IDLE -> (add streams) -> STREAMS (start) -> WORK (stop) -> STREAMS (start)
+ | WORK (pause) -> PAUSE (resume )---
+ | |
+ | |
+ ------------------------------------
+
+-----
+
+=== Tutorial
+
+First run trex in interactive mode
+
+[source,bash]
+----
+$sudo ./t-rex-64 -i
+----
+
+on the same machine from a different window connect to to trex
+
+[source,bash]
+----
+$./trex-console
+----
+
+
+from console you can run this
+
+[source,bash]
+----
+
+# start traffic on all port
+>start -a -m 1 -f stl/imix_1pkt.yaml
+
+# stop traffic on all port
+>stop -a
+
+# show dynamic statistic
+>tui
+
+#stop all and remove all stats
+>reset
+----
+
+=== Common Arguments
+
+This section includes arguments that are common to many commands
+In the command they will be marked like this (arg name)
+
+==== Port mask
+
+this gives the ability to choose batch of ports
+
+[source,bash]
+----
+$command [-a] [-port 1 2 3] [-port 0xff] [-port clients/servers]
+
+ port mask :
+ [-a] : all ports
+ [-port 1 2 3] : port 1,2 3
+ [-port 0xff] : port by mask 0x1 for port 0 0x3 for port 0 and 1
+ [-port clients/servers] : -port clients will choose all the client side ports
+----
+
+==== Duration
+
+duration in second or in min or hours
+
+[source,bash]
+----
+$command[-d 100] [-d 10m] [-d 1h]
+
+ duration:
+ -d 100 : in sec
+ -d 10m : in min
+ -d 1h : in hours
+----
+
+
+==== Multiplier
+
+[source,bash]
+----
+$command [-m 100] [-m 10gb] [-m 10kpps] [-m 40%]
+
+ multiplier :
+
+ -m 100 : multiply stream file by this factor
+ -m 10gb : from graph calculate the maximum rate as this bandwidth ( for each port )
+ -m 10kpps : from graph calculate the maximum rate as this pps ( for each port )
+ -m 40% : from graph calculate the maximum rate as this precent from total port ( for each port )
+----
+
+
+=== Commands
+
+
+==== Connect
+
+[source,bash]
+----
+
+$trex-con [--ip $IP] [--server $IP] [--rpc-port $PORT] [--async_port port]
+
+ --rpc-port : change the default server - default 5505 for RPC
+
+ --async_port : for sub/pub ZMQ - default 4505
+
+ --ip or --server :default 127.0.0.1 the TRex server ip
+----
+
+This command
+* try to connect to server
+* send ping command
+* sync with all the ports info / streams info state
+* read all counters stats for reference
+
+==== reset
+
+Reset the server and client to a known state - should not be used in a normal scenario
+
+[source,bash]
+----
+$reset
+----
+
+- force acuire all the ports
+- Stop all traffic on all the ports
+- Remove all the streams from all the ports
+
+
+==== port
+
+Configure port state, autoneg, rate etc
+
+[source,bash]
+----
+$port (port mask) --cfg "auto/10/"
+
+ --cfg string with the configuration name
+
+----
+
+
+==== clear
+
+Clear all port stats counters
+
+[source,bash]
+----
+$clear (port mask)
+----
+
+
+==== stats
+
+Shows global and port statistic
+
+[source,bash]
+----
+$stats (port mask) [-g] [-p] [-ps]
+
+ -g show only global stats
+ -p only ports stats
+ -ps only port status (type/driver/link-up/down/negotion type etc)
+
+----
+
+Examples
+
+
+[source,bash]
+----
+$stats -g
+
+Connected : 127.0.0.1 4500
+Version : 1.78 UUID : 12121212
+CPU : 12.0 %%
+Total TX : 20.2 Gb/sec
+Total Rx : 20.2 Gb/sec
+Total PPS : 100MPPS
+Total Streams : 10
+Active ports : 4
+----
+
+[source,bash]
+----
+$stats -p
+
+ port 0 1 2 3
+ ------------------------------------
+ owner my my my my - place holder no need to implement as we takes all port avali
+ active on on off off
+ tx-bytes 12131 0 0 0
+ rx-bytes 0 0 0 0
+ tx-pkts 0 0 0 0
+ rx-pkts 0 0 0 0
+ tx-errors 0 0 0 0
+ rx-errors 0 0 0 0
+ Tx-Bw 12gb 1.3Gb 0 0
+ Rx-Bw 10mb 11.2mb 0 0
+----
+
+In case of more than four ports should show only the first ports or by mask ( --port mask)
+
+
+[source,bash]
+----
+$stats -ps
+
+ --- port status
+ port 0 1 2 3
+ ------------------------------------
+ port-type I350 I350 I350 I350
+ maximum 1Gb 1Gb 1Gb !gb
+ link on on off off
+----
+
+
+==== streams
+
+Shows the configured streams on each port/ports
+Should show from client cache
+
+[source,bash]
+----
+$streams (port mask) [--streams mask] [-f] [--full] [--graph]
+
+ --port mask, e.g --port 1 2 3 4
+ --streams mask e.g. --streams 1 2
+ -f /--full print stream info in a JSON format with all the information
+ --graph : add the graph in time of each port stream
+----
+
+
+example
+
+[source,bash]
+----
+$streams
+
+port 0 : imix/a.yaml
+
+ stream id , packet type , length , mode , rate , next
+ + 0 , ip/tcp , 64 , continues , 100KPPS , none
+ + 1 , ip/udp , 128 , burst , 200KPPS , none
+ + 2 , ip/udp , 1500 , multi-burst , 100KPPS , none
+
+
+
+port 1 : imix/a.yaml
+
+ + 0 , ip/tcp , 64 , continues , 100KPPS , none
+ + 1 , ip/udp , 128 , burst , 200KPPS , none
+ + 2 , ip/udp , 1500 , multi-burst , 100KPPS , none
+
+----
+
+
+show only port 1 and 2
+
+[source,bash]
+----
+$streams --port 1 2
+
+ ..
+ ..
+----
+
+[source,bash]
+----
+$streams --port 0 --streams 0 -f
+
+
+ show the full info on stream 0 and port 0, print in JSON format
+
+----
+
+
+
+
+==== start
+
+* work on a set of ports
+* remove all streams
+* load new streams
+* start traffic with specific multiplier
+* limit the traffic to a specific duration
+* port state should be stopped, in case of --force stop the port
+* in case one of the port is not stop don't start any port
+* all ports should be in state IDLE or STREAMS
+
+[source,bash]
+----
+$start [--force] (port mask) [-f stl/imix.yaml] [-db ab] (duration) (multiplier)
+
+
+ stream to load:
+ -f stl/imix.yaml : load from local disk the streams file
+ --db stream that was loaded to db
+
+ force:
+ --force stop ports if they are active
+
+----
+
+examples
+
+
+[source,bash]
+----
+$start -a -f stl/imix.yaml -m 10gb
+----
+start this profile on all all ports maximum bandwidth is 10gb
+
+
+[source,bash]
+----
+$start -port 1 2 -f stl/imix.yaml -m 100
+----
+start this profile on port 1,2 multiply by 100
+
+
+[NOTE]
+=====================================
+ in case of start command without args, try to remember the last args given and reprint them
+=====================================
+
+==== stop
+
+* work on a set of ports
+* change the mode of the port to stopped
+* do not remove the streams
+* in case port state is already stopped don't do anything
+* all ports should be in state WORK
+
+
+[source,bash]
+----
+$stop (port mask)
+
+ See ports command explanation from the start
+
+----
+
+
+==== pause
+
+* work on a set of ports
+* move a wokring set of ports to a state of pause
+* all ports should be in state WORK
+
+
+
+[source,bash]
+----
+$pause (port mask)
+
+ see ports command explanation from start
+
+----
+
+
+==== resume
+
+* work on a set of ports
+* move a wokring set of port to a state of resume
+* all ports should be in state PAUSE
+
+
+
+[source,bash]
+----
+$resume (port mask)
+
+ see ports command explanation from start
+
+----
+
+
+==== restart
+
+* restart the work on the loaded streams
+* same as start without the -f /--db switch
+* all ports should be in state STREAMS
+
+[source,bash]
+----
+$restart (port mask) (duration) (multiplier)
+
+ see ports command explanation from start
+
+----
+
+==== update
+
+* all ports should be in state WORK
+
+
+[source,bash]
+----
+>update (port mask) (multiplier)
+----
+Update the bandwidth multiplier for a mask of ports
+
+
+[NOTE]
+=====================================
+ Here we could add the ability to disable/enable specific stream, load new stream dynamically etc.
+=====================================
+
+
+==== async events queue
+
+there are two ways to know if somthing async happned
+
+* pool the state
+* get async event
+
+example for events are:
+
+* link is up/down
+* port id stoped
+* port id start
+* errors
+* info
+
+
+[source,bash]
+----
+$clear_events
+----
+
+clear events queue
+
+[source,bash]
+----
+$show_events
+----
+show a list of events from the queue
+
+[source,bash]
+----
+$remove --event [event-id] --top
+ --event : remove the event-id from the list
+ --top : remove the even from the top
+----
+
+
+[source,bash]
+----
+$wait_for_event [event-id]
+----
+wait only in script mode, simple way to wait for event like all port stopped
+
+
+==== stream database commands
+
+* load/remove/show streams from memory
+
+
+[source,bash]
+----
+$db_load -f [stream ] -name [name]
+----
+
+[source,bash]
+----
+$db_remove -name [name]
+----
+
+[source,bash]
+----
+$db_show [--all] [--name $name] [--full]
+----
+
+
+==== script
+
+[source,bash]
+----
+$script -f script_name
+-----
+
+run script of commands
+
+
+==== tui
+
+shows the stats in a textual window (like top)
+
+[source,bash]
+----
+$tui
+----
+
+enter to a mode of Stats and present 3 type of windows
+* global/port stats/version/connected etc
+* per port
+* per port streams info
+
+
+get keyboard
+ q - quit the gui window
+ c - clear all counters
+
+
+=== Priorty
+
+* Console logger - JSON-RPC into a file ( req/res)
+* start/stop/stats/tui/streams/reset
+* db
+* port
+* events
+* pause/resume/restart/restart
+* scripts
+* move all the debug commands to be dbg_xxx
+* implement advance -m ( by reading graphs)
+* Enforcement of one user/port with R/W capability
+
+=== More ideas
+
+* define a YAML format that include stream per port inside so in away load each YAML to each port
+* add ability to load range of ip/mac program in YAML file
+ fields :
+ name : ipv4.src
+ offset : 12
+ range :
+ min_ip : 10.0.0.1/ipv6 addr
+ max_ip : 10.0.0.20
+ inc : 1
+ dec : 1
+ start : 10.0.0.4
+
+ name : ipv4.dest
+ offset : 45
+ range :
+ min_ip : 10.0.0.1
+ max_ip : 10.0.0.2
+
+
+=== Change log
+
+[options="header",cols="^1,^h,3a"]
+|=================
+| Version | name | meaning
+| 1.00 | Hanoch Haim (hhaim) |
+- first version
+| 1.01 | Hanoch Haim (hhaim) |
+- Incorporate Itay comments
+|=================
+
+
+
diff --git a/doc/trex_control_plane_design_phase1.asciidoc b/doc/trex_control_plane_design_phase1.asciidoc
new file mode 100755
index 00000000..b9454b09
--- /dev/null
+++ b/doc/trex_control_plane_design_phase1.asciidoc
@@ -0,0 +1,519 @@
+TRex Control Plane Design - Phase 1
+====================================
+:author: Dan Klein
+:email: <danklei@cisco.com>
+:revnumber: 1.0
+:quotes.++:
+:numbered:
+
+
+include::trex_ga.asciidoc[]
+
+
+== Introduction
+
+=== TRex traffic generator
+
+TRex traffic generator is a tool design the benchmark platforms with realistic traffic.
+This is a work-in-progress product, which is under constant developement, new features are added and support for more router's fuctionality is achieved.
+
+=== TRex Control Plane
+
+TRex control (phase 1) is the base API, based on which any future API will be developed. +
+This document will describe the current control plane for TRex, and its scalable features as a directive for future developement.
+
+==== TRex Control Plane - Architecture and Deployment notes
+
+TRex control plane is based on a JSON RPC transactions between clients and server. +
+Each TRex machine will have a server running on it, closely interacting with TRex (clients do not approach TRex directly). +
+The server version (which runs as either a daemon or a CLI application) is deployed with TRex latest version, written in Python 2.7.
+As future feature, and as multiple T-Rexes might run on the same machine, single server shall serve all T-Rexes running a machine.
+
+The control plane implementation is using the currently dumped data messaging from TRex's core via ZMQ publisher, running from core #1.
+The server used as a Subscriptor for this data, manipulating the packets, and re-encodes it into JSON-RPC format for clients use. +
+Since the entire process is taken place internally on the machine itself (using TCP connection with `localhost`), very little overhead is generated from outer network perspective.
+
+<<<
+
+The following image describes the general architecture of the control plane and how it interacts with the data plane of TRex.
+
+ifdef::backend-docbook[]
+image::images/trex_control_plane_modules.png[title="Control Plane modules",align="center",width=450, link="images/trex_control_plane_modules.png"]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+image::images/trex_control_plane_modules.png[title="Control Plane modules",align="center",width=900, link="images/trex_control_plane_modules.png"]
+endif::backend-xhtml11[]
+
+The Python test script block represents any automation code or external module that wishes to control TRex by interacting with its server.
+
+Such script can use other JSON-RPC based implementations of this CTRexClient module, as long as it corresponds with the known server methods and JSON-RPC protocol.
+
+At next phases, an under developement integrated module will serve the clients, hence eliminating even the internal TCP messaging on the machine footnote:[updating server side planned to have almost no affect on the client side].
+
+== Using the API
+
+[NOTE]
+Basic familiarity with TRex is recommended before using this tool. +
+Further information can be learned from TRex manual: http://csi-wiki-01:8080/display/bpsim/Documentation[(TRex manual)]
+
+
+=== The Server module
+
+The server module is responsible for handling all possible requests related to TRex (i.e. this is the only mechanism that interacts with remote clients). +
+The server is built as a multithreaded application, and **must be launched on a TRex commands using `sudo` permissions**.
+
+The server application can run in one of two states:
+
+ 1. **Live monitor**: this will run the server with live logging on the screen. To launch the server in this mode run `server/trex_server.py` file directly.
+
+ 2. **Daemon application**: this will run the server as a background daemon process, and all logging will be saved into file, located at `/var/log/trex/` path. +
+ This is the common scenario, during which nothing is prompted into the screen, unless in case of error in server launching.
+
+==== Launching the server
+
+The server would run only on valid TRex machines or VM, due to delicate customization in used sub-modules, designed to eliminate the situation in which control and data plane packets are mixed.
+
+The server code is deployed by default with TRex (starting version 1.63 ) and can be launched from its path using the following command: +
+`./trex_daemon_server [RUN_COMMAND] [options]`
+
+[NOTE]
+The [RUN_COMMAND] is used only when server launched as a daemon application.
+
+Running this command with `--help` option will prompt the help menu, explaning all the available options.
+
+===== Daemon commands
+
+The following daemon commands are supported:
+
+ 1. **`start`**: This option starts the daemon application of TRex server, using the following command options (detailed exmplanation on this next time).
+
+ 2. **`stop`**: Stop the daemon application.
+
+ 3. **`restart`**: Stop the current daemon proccess, then relaunch it with the provided parameters (the parameters must be re-entered).
+
+ 3. **`show`**: Prompt whether the daemon is running or not.
+
+WARNING: restarting the daemon application will **truncate** the logfile.
+
+===== Server options commands
+
+The following describes the options for server launching, and applies to both daemon and live launching. +
+Let's have a look on the help menu:
+
+----
+[root@trex-dan Server]# ./trex_daemon_server --help
+[root@trex-dan Server]# usage: trex_deamon_server {start|stop|restart} [options]
+
+ NOTE: start/stop/restart options only available when running in daemon mode
+
+Run server application for TRex traffic generator
+
+optional arguments:
+ -h, --help show this help message and exit
+ -p PORT, --daemon-port PORT
+ Select port on which the daemon runs. Default port is
+ 8090.
+ -z PORT, --zmq-port PORT
+ Select port on which the ZMQ module listens to TRex.
+ Default port is 4500. #<2>
+ -t PATH, --trex-path PATH
+ Specify the compiled TRex directory from which TRex
+ would run. Default path is: / #<1>
+
+[root@trex-dan Server]#
+----
+
+<1> Default path might change when launching the server in daemon or live mode.
+
+<2> ZMQ port must match the defined port of the platform, generally found at `/etc/trex_cfg.yaml`.
+
+The available options are:
+
+ 1. **`-p, --daemon-port`**: set the port on which the server is listening to clients requests. +
+ Default listening server port is **`8090`**.
+
+ 2. **`-z, --zmq-port`**: set the port on which the server is listening to zmq publication from TRex. +
+ Default listening server port is **`4500`**.
+
+ 3. **`-t, --trex-path`**: set the path from which TRex is runned. This is especially helpful when more than one version of TRex is used or switched between. Although this field has default value, it is highly recommended to set it manually with each server launch.
+
+[NOTE]
+When server is launched is first makes sure the trex-path is valid: the path 'exists' and granted with 'execution permissions.' If any of the conditions is not valid, the server will not launch.
+
+
+=== The Client module
+
+The client is a Python based application that created `TRexClient` instances. +
+Using class methods, the client interacts with TRex server, and enable it to perform the following commands:
+
+ 1. Start TRex run (custom parameters supported).
+
+ 2. Stop TRex run.
+
+ 3. Check what is the TRex status (possible states: `Idle, Starting, Running`).
+
+ 4. Poll (by customize sampling) the server and get live results from TRex **while still running**.
+
+ 5. Get custom TRex stats based on a window of saved history of latest 'N' polling results.
+
+The clients is also based on Python 2.7, however unlike the server, it can run on any machine who wishes to. +
+In fact, the client side is simply a python library that interact with the server using JSON-RPC (v2), hence if needed, anyone can write a library on any other language that will interact with the server ins the very same way.
+
+
+==== `CTRexClient` module initialization
+
+As explained, `CTRexClient` is the main module to use when writing an TRex test-plan. +
+This module holds the entire interaction with TRex server, and result containing via `result_obj`, which is an instance of `CTRexResult` class. +
+The `CTRexClient` instance is initialized in the following way:
+
+ 1. **TRex hostname**: represents the hostname on which the server is listening. Either hostname or IPv4 address will be a valid input.
+
+ 2. **Server port**: the port on which the server listens to incoming client requests. This parameter value must be identical to `port` option configured in the server.
+
+ 3. **History size**: The number of saved TRex samples. Based on this "window", some extra statistics and data are calculated. Default history size is 100 samples.
+
+ 4. **verbose **: This boolean option will prompt extended output, if available, of each of the activated methods. For any method that interacts with TRex server, this will prompt the JSON-RPC request and response. +
+ This option is especially useful for developers who wishes to imitate the functionality of this client using other programming languages.
+
+**That's it!** +
+Once these parameter has been passed, you're ready to interact with TRex.
+
+[NOTE]
+The most common initialization will simply use the hostname, such that common initilization lookes like: +
+`trex = CTRexClient('trex_host_name')`
+
+==== `CTRexClient` module usage
+
+This section covers with great detail the usage of the client module. Each of the methods describes are class methods of `CTRexClient`.
+
+ - **`start_trex (f, d, block_to_success, timeout, trex_cmd_options)`** +
+ Issue a request to start TRex with certain configuration. The server will only handle the request if the TRex is in `Idle` status. +
+ Once the status has been confirmed, TRex server will issue for this single client a token, so that only that client may abort running TRex session. +
+ `f` and `d` parameters are mandatory, as they are crucial parameter in setting TRex behaviour. Also, `d` parameter must be at least 30 seconds or larger.
+ By default (and by design) this method **blocks** until TRex status changes to either 'Running' or back to 'Idle'.
+
+ - **`stop_trex()`** +
+ If (and only if) a certain client issued a run requested (and it accepted), this client may use this command to abort current run. +
+ This option is very useful especially when the real-time data from the TRex are utilized.
+
+ - **`wait_until_kickoff_finish(timeout = 40)`** +
+ This method blocks until TRex status changes to 'Running'. In case of error an exception will be thrown. +
+ The 'timeout' parameter sets the maximum waiting time. +
+ This method is especially useful when `block_to_success` was set to false in order to utilize the time to configure other things, such as DUT.
+
+ - **`is_running(dump_out = False)`** +
+ Checks if there's currently TRex session up (with any client). +
+ If TRex is running, this method returns `True` and the result object id updated accordingly. +
+ If not running, return `False`. +
+ If a dictionary pointer is given in `dump_out` argument, the pointer object is cleared and the latest dump stored in it.
+
+ - **`get_running_status()`** +
+ Fetches the current TRex status. +
+ Three possible states
+
+ * `Idle` - No TRex session is currently running.
+
+ * `Starting` - A TRex session just started (turns into Running after stability condition is reached)
+
+ * `Running` - TRex session is currently active.
+
+ The following diagram describes the state machine of TRex:
+
+ifdef::backend-docbook[]
+image::images/trex_control_plane_state_machine.png[title="TRex running state machine",align="center",width=280, link="images/trex_control_plane_state_machine.png"]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+image::images/trex_control_plane_state_machine.png[title="TRex running state machine",align="center",width=400, link="images/trex_control_plane_state_machine.png"]
+endif::backend-xhtml11[]
+
+ - **`get_running_info()`** +
+ This method performs single poll of TRex running data and process it into the result object (named `result_obj`). +
+ The method returns the most updated data dump from TRex in the form of Python dictionary. +
+ +
+ Behind the scenes, running that method will trigger inner-client process over the saved window, and produce window-relevant information, as well as get the most important data more accessible. +
+ Once the data has been fetched (at sample rate the satisfies the user), a custom data manipulation can be done in various forms and techniques footnote:[See `CTRexResult` module usage for more details]. +
+ **Note: ** the sampling rate is bounded from buttom to 2 samples/sec.
+
+ - **`sample_until_condition(condition_func, time_between_samples = 5)`** +
+ This method automatically sets ongoing sampling of TRex data, with sampling rate described by `time_between_samples`. On each fetched dump, the `condition_func` is applied on the result objects, and if returns `True`, the sampling will stop. +
+ On success (condition has been met), this method returns the latest result object that satisfied the given condition. +
+ ON fail, this method will raise `UserWarning` exception.
+
+ - **`sample_to_run_finish(time_between_samples = 5)`** +
+ This method automatically sets ongoing sampling of TRex data with sampling rate described by `time_between_samples` until TRex run finished.
+
+ - **`get_result_obj()`** +
+ Returns a pointer to the result object of the client instance. +
+ Hence, this method returns the result object on which all the data processing takes place.
+
+TIP: The window stats (calculated when `get_running_info()` triggered) are very helpful in eliminate 'spikes' behavior in numerical values which might float from other data.
+
+==== `CTRexResult` module usage
+
+This section covers how to use `CTRexResult` module to access into TRex data and post processing results, taking place at the client side whenever a data is polled from the server. +
+The most important data structure in this module is the `history` object, which contains the sampled information (plus the post processing step) of each sample.
+
+Most of the class methods are getters that enables an easy access to the most commonly used when working with TRex. These getters are called with self-explained names, such as `get_max_latency`. +
+However, on top to these methods, the class offers data accessibility using the rest of the class methods. +
+These methods are:
+
+ - **`is_done_warmup()`** +
+ This will return `True` only if TRex has reached its expected transmission bandwidth footnote:[A 3% deviation is allowed.]. +
+ This parameter is important since in most cases, the most relevent test cases are interesting when TRex produces its expected TX, based on which the platform is tested and benchmerked.
+
+ - **`get_latest_dump()`** +
+ Fetches the latest polled dump saved in history.
+
+ - **`get_last_value (tree_path_to_key, regex = None)`** +
+ Fetch, out of the latest data dump a value.
+
+ - **`get_value_list (tree_path_to_key, regex = None)`** +
+ Fetch, out of all data dumps stored in history a value.
+
+ - **History data access API** +
+ Since (as mentioned earlier) the data dump is a JSON-RPC string, which is decoded into Python dictionaries and lists, nested within each other. +
+ This "Mini API" is used by both `get_last_value` and `get_value_list` methods, and receives in both cases two arguments: `tree_path_to_key, regex` footnote:[By default, `regex` argument is set to None]. +
+ The user may choose whatever value he wishes to extract, using the `tree_path_to_key` argument.
+
+ * In order to get deeper and deeper on the hierarchy, use the key of the dictionary, separated by dot (‘'.'’) for each level. +
+ In order to fetch more than one key in a certain dictionary (no matter how deep it is nested), use the `regex` argument to state which keys are to be included.
+ Example: In order to fetch only the `expected_tx` key values of the latest dump, we'll call: *`get_last_value("trex-global.data", "m_tx_expected_\w+")`* +
+ This will produce the following dictionary result: +
+ *`{'m_tx_expected_pps': 21513.6, 'm_tx_expected_bps': 100416760.0, 'm_tx_expected_cps': 412.3}`* +
+ We can see that the result is every key-value pair, found at the relevant tree-path and matches the provided regex.
+
+ * In order to access an array element, specifying the `key_to_array[i]`, where `i` is the desired array index. +
+ Example: In order to access the third element of the data array of: +
+ `{“template_info†: {"name":"template_info","type":0,"data":["avl/delay_10_http_get_0.pcap","avl/delay_10_http_post_0.pcap",` *`"avl/delay_10_https_0.pcap"`* `,"avl/delay_10_http_browsing_0.pcap", "avl/delay_10_exchange_0.pcap","avl/delay_10_mail_pop_0.pcap","avl/delay_10_mail_pop_1.pcap","avl/delay_10_mail_pop_2.pcap","avl/delay_10_oracle_0.pcap"]}` +
+ we'll use the following command: `get_last_value("template_info.data[2]â€)`. +
+ This will produce the following result: +
+ *`avl/delay_10_https_0.pcap`* +
+
+
+== Usage Examples
+
+=== Example #1: Checking TRex status and Launching TRex
+
+The following program checks TRex status, and later on launches it, querying its status along different time slots.
+
+[source, python]
+----
+import time
+
+trex = CTRexClient('trex-name')
+print "Before Running, TRex status is: ", trex.is_running() # <1>
+print "Before Running, TRex status is: ", trex.get_running_status() # <2>
+
+ret = trex.start_trex( c = 2, # <3>
+ m = 0.1,
+ d = 40,
+ f = 'avl/sfr_delay_10_1g.yaml',
+ nc = True,
+ p = True,
+ l = 1000)
+
+print "After Starting, TRex status is: ", trex.is_running(), trex.get_running_status()
+
+time.sleep(10) # <4>
+
+print "Is TRex running? ", trex.is_running(), trex.get_running_status() # <5>
+----
+
+<1> `is_running()` returns a boolean and checks if TRex is running or not.
+
+<2> `get_running_status()` returns a Python dictionary with TRex state, along with a verbose field containing extra info, if available.
+
+<3> TRex lanching. All types of inputs are supported. Some fields (such as 'f' and 'd' are mandatory).
+
+<4> Going to sleep for few seconds, allowing TRex to start.
+
+<5> Checking out with TRex status again, printing both a boolean return value and a full status.
+
+This code will prompt the following output, assuming a server was launched on the TRex machine.
+
+----
+Connecting to TRex @ http://trex-dan:8090/ ...
+Before Running, TRex status is: False
+Before Running, TRex status is: {u'state': <TRexStatus.Idle: 1>, u'verbose': u'TRex is Idle'}
+ <1> <1>
+
+After Starting, TRex status is: False {u'state': <TRexStatus.Starting: 2>, u'verbose': u'TRex is starting'}
+ <1> <1>
+Is TRex running? True {u'state': <TRexStatus.Running: 3>, u'verbose': u'TRex is Running'}
+ <1> <1>
+----
+
+<1> When looking at TRex status, both an enum status (`Idle, Starting, Running`) and verbose output are available.
+
+
+=== Example #2: Checking TRex status and Launching TRex with 'BAD PARAMETERS'
+
+The following program checks TRex status, and later on launches it with wrong input ('mdf' is not legal option), hence TRex run will not start and a message will be available.
+
+[source, python]
+----
+import time
+
+trex = CTRexClient('trex-name')
+print "Before Running, TRex status is: ", trex.is_running() # <1>
+print "Before Running, TRex status is: ", trex.get_running_status() # <2>
+
+ret = trex.start_trex( c = 2, # <3>
+#<4> mdf = 0.1,
+ d = 40,
+ f = 'avl/sfr_delay_10_1g.yaml',
+ nc = True,
+ p = True,
+ l = 1000)
+
+print "After Starting, TRex status is: ", trex.is_running(), trex.get_running_status()
+
+time.sleep(10) # <5>
+
+print "Is TRex running? ", trex.is_running(), trex.get_running_status() # <6>
+----
+
+<1> `is_running()` returns a boolean and checks if TRex is running or not.
+
+<2> `get_running_status()` returns a Python dictionary with TRex state, along with a verbose field containing extra info, if available.
+
+<3> TRex lanching. All types of inputs are supported. Some fields (such as 'f' and 'c' are mandatory).
+
+<4> Wrong parameter ('mdf') injected.
+
+<5> Going to sleep for few seconds, allowing TRex to start.
+
+<6> Checking out with TRex status again, printing both a boolean return value and a full status.
+
+This code will prompt the following output, assuming a server was launched on the TRex machine.
+----
+Connecting to TRex @ http://trex-dan:8090/ ...
+Before Running, TRex status is: False
+Before Running, TRex status is: {u'state': <TRexStatus.Idle: 1>, u'verbose': u'TRex is Idle'}
+ <1> <1>
+
+After Starting, TRex status is: False {u'state': <TRexStatus.Starting: 2>, u'verbose': u'TRex is starting'}
+ <1> <1>
+Is TRex running? False {u'state': <TRexStatus.Idle: 1>, u'verbose': u'TRex run failed due to wrong input parameters, or due to reachability issues.'}
+ <2> <2>
+----
+
+<1> When looking at TRex status, both an enum status (`Idle, Starting, Running`) and verbose output are available.
+
+<2> After TRex lanuching failed, a message indicating the failure reason. However, TRex is back Idle, ready to handle another launching request.
+
+
+=== Example #3: Launching TRex, let it run until custom condition is satisfied
+
+The following program will launch TRex, and poll its result data until custom condition function returns `True`. + In this case, the condition function is simply named `condition`. +
+Once the condition is met, TRex run will be terminated.
+
+[source, python]
+----
+print "Before Running, TRex status is: ", trex.get_running_status()
+
+ print "Starting TRex..."
+ ret = trex.start_trex( c = 2,
+ mdf = 0.1,
+ d = 1000,
+ f = 'avl/sfr_delay_10_1g.yaml',
+ nc = True,
+ p = True,
+ l = 1000)
+
+ def condition (result_obj): #<1>
+ return result_obj.get_current_tx_rate()['m_tx_pps'] > 200000
+
+ res = trex.sample_until_condition(condition) #<2>
+
+ print res #<3>
+ val_list = res.get_value_list("trex-global.data", "m_tx_expected_\w+") #<4>
+----
+
+<1> The `condition` function defines when to stop TRex. In this case, when TRex's current tx (in pps) exceeds 200000.
+
+<2> The condition is passed to `sample_until_condition` method, which will block until either the condition is met or an 'Exception' is raised.
+
+<3> Once satisfied, `res` variable holds the first result object on which the condition satisfied. At this point, TRex status is 'Idle' and another run can be requested from the server.
+
+<4> Further custom processing can be made on the result object, regardless of other TRex runs.
+
+<<<
+
+=== Example #4: Launching TRex, monitor live data and stopping on demand
+
+The following program will launch TRex, and while it runs poll the server (every 5 seconds) for running inforamtion, such as latency, drops, and other extractable parameters. +
+Then, after some criteria was met, TRex execution is terminated, enabeling others to use the resource instead of waiting for the entire execution to finish.
+
+[source, python]
+----
+print "Before Running, TRex status is: ", trex.get_running_status()
+
+ print "Starting TRex..."
+ ret = trex.start_trex( c = 2,
+ mdf = 0.1,
+ d = 100,
+ f = 'avl/sfr_delay_10_1g.yaml',
+ nc = True,
+ p = True,
+ l = 1000)
+
+ last_res = dict()
+ while trex.is_running(dump_out = last_res): #<1>
+ print '\n\n*****************************************'
+ print "RECEIVED DUMP:"
+ print last_res, "\n\n\n"
+
+ print "CURRENT RESULT OBJECT"
+ obj = trex.get_result_obj()
+ #<2> # Custom data processing is done here, for example:
+ print obj.get_value_list("trex-global.data.m_tx_bps")
+ time.sleep(5) #<3>
+
+ print "Terminating TRex..."
+ ret = trex.stop_trex() #<4>
+----
+
+<1> Iterate as long as TRex is running. +
+ In this case the latest dump is also saved into `last_res` variable, so easier access for that data is available, although not needed most of the time.
+
+<2> Data processing. This is fully customizable for the relevant test initiated.
+
+<3> The sampling rate is flexibale and can be configured depending on the desired output.
+
+<4> TRex termination.
+
+<<<
+
+=== Example #5: Launching TRex, let it run until finished
+
+The following program will launch TRex, and poll it automatically until run finishes. The polling rate is customisable (in this case, every 10 seconds) using `time_between_samples` argument.
+
+[source, python]
+----
+print "Before Running, TRex status is: ", trex.get_running_status()
+
+ print "Starting TRex..."
+ ret = trex.start_trex( c = 2, #<1>
+ mdf = 0.1,
+ d = 1000,
+ f = 'avl/sfr_delay_10_1g.yaml',
+ nc = True,
+ p = True,
+ l = 1000)
+
+ res = trex.sample_to_run_finish(time_between_samples = 10) #<2>
+
+ print res #<3>
+ val_list = res.get_value_list("trex-global.data", "m_tx_expected_\w+") #<4>
+----
+
+<1> TRex run initialization.
+
+<2> Define the sample rate and block until TRex run ends. Once this method returns (assuming no error), TRex result object will contain the samples collected allong TRex run, limited to the history size footnoteref:[For example, For example for history sized 100 only the latest 100 samples will be available despite sampling more than that during TRex run.].
+
+<3> Once finished, `res` variable holds the latest result object.
+
+<4> Further custom processing can be made on the result object, regardless of other TRex runs. \ No newline at end of file
diff --git a/doc/trex_control_plane_peek.asciidoc b/doc/trex_control_plane_peek.asciidoc
new file mode 100755
index 00000000..ce923d0b
--- /dev/null
+++ b/doc/trex_control_plane_peek.asciidoc
@@ -0,0 +1,227 @@
+TRex Stateful Python API Tutorial
+=================================
+:author: Dan Klein
+:email: <danklei@cisco.com>
+:revnumber: 1.0
+:quotes.++:
+:numbered:
+
+
+include::trex_ga.asciidoc[]
+
+
+=== TRex traffic generator
+
+TRex traffic generator is a tool design the benchmark platforms with realistic traffic.
+This is a work-in-progress product, which is under constant developement, new features are added and support for more router's fuctionality is achieved.
+
+=== TRex Control
+
+TRex control plane is under developement, and a phase 1 is planned to be published soon (Apr 2015). +
+This document will shortly describe the planned control plane for TRex, which is planned to be more scalable and support automation more intuitively.
+
+==== TRex Control Plane - High Level
+
+TRex control plane is based on a JSON RPC transactions between clients and server. +
+Each TRex machine will have a server running on it, closely interacting with TRex (clients do not approach TRex directly). +
+As future feature, and as multiple T-Rexes might run on the same machine, single server shall serve all T-Rexes running a machine.
+
+The client is a Python based application that created `TRexClient` instances. +
+Using class methods, the client interacts with TRex server, and enable it to perform the following commands:
+
+ 1. Start TRex run (custom parameters supported).
+
+ 2. Stop TRex run.
+
+ 3. Check what is the TRex status (possible states: `Idle, Starting, Running`).
+
+ 4. Poll (by customize sampling) the server and get live results from TRex **while still running**.
+
+ 5. Get custom TRex stats based on a window of saved history of latest 'N' polling results.
+
+
+==== TRex Control Plane - Example crumbs
+
+
+
+ - **Exmaple #1: Checking TRex status and Launching TRex**
+ The following program checks TRex status, and later on launches it, querying its status along different time slots.
+
+[source, python]
+----
+import time
+
+trex = CTRexClient('trex-name')
+print "Before Running, TRex status is: ", trex.is_running() # <1>
+print "Before Running, TRex status is: ", trex.get_running_status() # <2>
+
+ret = trex.start_trex( c = 2, # <3>
+ m = 0.1,
+ d = 20,
+ f = 'avl/sfr_delay_10_1g.yaml',
+ nc = True,
+ p = True,
+ l = 1000)
+
+print "After Starting, TRex status is: ", trex.is_running(), trex.get_running_status()
+
+time.sleep(10) # <4>
+
+print "Is TRex running? ", trex.is_running(), trex.get_running_status() # <5>
+----
+
+<1> `is_running()` returns a boolean and checks if TRex is running or not.
+
+<2> `get_running_status()` returns a Python dictionary with TRex state, along with a verbose field containing extra info, if available.
+
+<3> TRex lanching. All types of inputs are supported. Some fields (such as 'f' and 'c' are mandatory).
+
+<4> Going to sleep for few seconds, allowing TRex to start.
+
+<5> Checking out with TRex status again, printing both a boolean return value and a full status.
+
+This code will prompt the following output, assuming a server was launched on the TRex machine.
+
+----
+Connecting to TRex @ http://trex-dan:8090/ ...
+Before Running, TRex status is: False
+Before Running, TRex status is: {u'state': <TRexStatus.Idle: 1>, u'verbose': u'TRex is Idle'}
+ <1> <1>
+
+After Starting, TRex status is: False {u'state': <TRexStatus.Starting: 2>, u'verbose': u'TRex is starting'}
+ <1> <1>
+Is TRex running? True {u'state': <TRexStatus.Running: 3>, u'verbose': u'TRex is Running'}
+ <1> <1>
+----
+
+<1> When looking at TRex status, both an enum status (`Idle, Starting, Running`) and verbose output are available.
+
+
+ * **Exmaple #2: Checking TRex status and Launching TRex with 'BAD PARAMETERS'**
+ The following program checks TRex status, and later on launches it with wrong input ('mdf' is not legal option), hence TRex run will not start and a message will be available.
+
+[source, python]
+----
+import time
+
+trex = CTRexClient('trex-name')
+print "Before Running, TRex status is: ", trex.is_running() # <1>
+print "Before Running, TRex status is: ", trex.get_running_status() # <2>
+
+ret = trex.start_trex( c = 2, # <3>
+#<4> mdf = 0.1,
+ d = 20,
+ f = 'avl/sfr_delay_10_1g.yaml',
+ nc = True,
+ p = True,
+ l = 1000)
+
+print "After Starting, TRex status is: ", trex.is_running(), trex.get_running_status()
+
+time.sleep(10) # <5>
+
+print "Is TRex running? ", trex.is_running(), trex.get_running_status() # <6>
+----
+
+<1> `is_running()` returns a boolean and checks if TRex is running or not.
+
+<2> `get_running_status()` returns a Python dictionary with TRex state, along with a verbose field containing extra info, if available.
+
+<3> TRex lanching. All types of inputs are supported. Some fields (such as 'f' and 'c' are mandatory).
+
+<4> Wrong parameter ('mdf') injected.
+
+<5> Going to sleep for few seconds, allowing TRex to start.
+
+<6> Checking out with TRex status again, printing both a boolean return value and a full status.
+
+This code will prompt the following output, assuming a server was launched on the TRex machine.
+----
+Connecting to TRex @ http://trex-dan:8090/ ...
+Before Running, TRex status is: False
+Before Running, TRex status is: {u'state': <TRexStatus.Idle: 1>, u'verbose': u'TRex is Idle'}
+ <1> <1>
+
+After Starting, TRex status is: False {u'state': <TRexStatus.Starting: 2>, u'verbose': u'TRex is starting'}
+ <1> <1>
+Is TRex running? False {u'state': <TRexStatus.Idle: 1>, u'verbose': u'TRex run failed due to wrong input parameters, or due to reachability issues.'}
+ <2> <2>
+----
+
+<1> When looking at TRex status, both an enum status (`Idle, Starting, Running`) and verbose output are available.
+
+<2> After TRex lanuching failed, a message indicating the failure reason. However, TRex is back Idle, ready to handle another launching request.
+
+
+ * **Exmaple #3: Launching TRex, monitor live data and stopping on demand**
+ The following program will launch TRex, and while it runs poll the server (every 5 seconds) for running inforamtion, such as latency, drops, and other extractable parameters. +
+ Then, after some criteria was met, TRex execution is terminated, enabeling others to use the resource instead of waiting for the entire execution to finish.
+
+[source, python]
+----
+print "Before Running, TRex status is: ", trex.get_running_status()
+
+ print "Starting TRex..."
+ ret = trex.start_trex( c = 2,
+ mdf = 0.1,
+ d = 100,
+ f = 'avl/sfr_delay_10_1g.yaml',
+ nc = True,
+ p = True,
+ l = 1000)
+
+ print "After Starting, TRex status is: ", trex.is_running(), trex.get_running_status()
+ print "sleeping 20 secs.."
+ time.sleep(20)
+ for i in range(5):
+ print "Is TRex running? ", trex.is_running(), trex.get_running_status() #<1>
+ #<2> received_info = trex.get_running_info()
+ #<3> # Custom data processing is done here
+ #<4> time.sleep(5)
+
+ print "Terminating TRex..."
+ #<5> ret = trex.stop_trex()
+ print "After stopping, TRex status is: ", trex.is_running(), trex.get_running_status() #<6>
+----
+
+<1> Running queries is still optional, although not mandatory in order to get stats.
+
+<2> `get_running_info()` will return the latest data dump available from TRex. +
+ Some aditional data manipulation and queries are under developement, including manipulation over number of dumps, which is useful for avoiding "spikes" of singular behavior.
+
+<3> Data processing. This is fully customizable for the relevant test initiated.
+
+<4> The sampling rate is flexibale and can be configured depending on the desired output.
+
+<5> TRex termination.
+
+<6> Post-termination check for status.
+
+
+This code will prompt the following output, assuming a server was launched on the TRex machine.
+----
+Connecting to TRex @ http://trex-dan:8090/ ...
+Before Running, TRex status is: False
+Before Running, TRex status is: {u'state': <TRexStatus.Idle: 1>, u'verbose': u'TRex is Idle'}
+Starting TRex...
+After Starting, TRex status is: False {u'state': <TRexStatus.Starting: 2>, u'verbose': u'TRex is starting'}
+
+<1> Is TRex running? True {u'state': <TRexStatus.Running: 3>, u'verbose': u'TRex is Running'}
+
+<1> Is TRex running? True {u'state': <TRexStatus.Running: 3>, u'verbose': u'TRex is Running'}
+
+<1> Is TRex running? True {u'state': <TRexStatus.Running: 3>, u'verbose': u'TRex is Running'}
+
+<1> Is TRex running? True {u'state': <TRexStatus.Running: 3>, u'verbose': u'TRex is Running'}
+
+<1> Is TRex running? True {u'state': <TRexStatus.Running: 3>, u'verbose': u'TRex is Running'}
+
+Before terminating, TRex status is: True {u'state': <TRexStatus.Running: 3>, u'verbose': u'TRex is Running'}
+Terminating TRex...
+#<2> After stopping, TRex status is: False {u'state': <TRexStatus.Idle: 1>, u'verbose': u'TRex finished (terminated).'}
+
+----
+
+<1> Polling TRex status while in a data polling loop.
+
+<2> After termination, we can see that TRex is back idle, also the `verbose` field shows the stop reason \ No newline at end of file
diff --git a/doc/trex_faq-docinfo.html b/doc/trex_faq-docinfo.html
new file mode 100644
index 00000000..a444f506
--- /dev/null
+++ b/doc/trex_faq-docinfo.html
@@ -0,0 +1,22 @@
+
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+
+<script src="my_chart.js"></script>
+
+<style>
+.axis path,
+.axis line {
+ fill: none;
+ stroke: #000;
+ shape-rendering: crispEdges;
+}
+
+.dot {
+ stroke: #000;
+}
+</style>
+
+
+
+
+
diff --git a/doc/trex_faq.asciidoc b/doc/trex_faq.asciidoc
new file mode 100644
index 00000000..44f4f237
--- /dev/null
+++ b/doc/trex_faq.asciidoc
@@ -0,0 +1,444 @@
+TRex Frequently Asked Questions
+================================
+:author: TRex team
+:email: trex.tgen@gmail.com
+:revnumber: 0.2
+:quotes.++:
+:numbered:
+:web_server_url: http://trex-tgn.cisco.com/trex
+:local_web_server_url: csi-wiki-01:8181/trex
+:github_stl_path: https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/stl
+:github_stl_examples_path: https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/automation/trex_control_plane/stl/examples
+:toclevels: 6
+
+include::trex_ga.asciidoc[]
+
+// PDF version - image width variable
+ifdef::backend-docbook[]
+:p_width: 450
+:p_width_1: 200
+:p_width_1a: 100
+:p_width_1c: 150
+:p_width_lge: 500
+endif::backend-docbook[]
+
+// HTML version - image width variable
+ifdef::backend-xhtml11[]
+:p_width: 800
+:p_width_1: 400
+:p_width_1a: 650
+:p_width_1a: 400
+:p_width_lge: 900
+endif::backend-xhtml11[]
+
+
+== FAQ
+
+=== General
+
+==== What is TRex?
+TRex is fast realistic open source traffic generation tool, running on standard Intel processors, based on DPDK. It supports both stateful and stateless traffic generation modes.
+
+==== What are the common use cases for TRex?
+1. High scale benchmarks for stateful networking gear. For example: Firewall/NAT/DPI.
+2. Generating high scale DDOS attacks. See link:https://www.incapsula.com/blog/trex-traffic-generator-software.html[Why TRex is Our Choice of Traffic Generator Software]
+3. High scale, flexible testing for switchs (e.g. RFC2544)- see link:https://wiki.fd.io/view/CSIT[fd.io]
+4. Scale tests for huge numbers of clients/servers for controller based testing.
+5. EDVT and production tests.
+
+[NOTE]
+=====================================
+Features terminating TCP can not be tested yet.
+=====================================
+
+==== Who uses TRex?
+
+Cisco systems, Intel, Imperva, Melanox, Vasona networks and much more.
+
+==== What are the Stateful and Stateless modes of operation?
+
+``Stateful'' mode is meant for testing networking gear which save state per flow (5 tuple). Usually, this is done by injecting pre recorded cap files on pairs of interfaces of the device under test, changing src/dst IP/port.
+``Stateless'' mode is meant to test networking gear, not saving state per flow (doing the decision on per packet bases). This is usually done by injecting customed packet streams to the device under test.
+See link:trex_stateless.html#_stateful_vs_stateless[here] for more details.
+
+==== Can TRex run on an hypervisor with virtual NICS?
+
+Yes. Currently there is a need for 2-3 cores and 4GB memory. For VM use case, memory requirement can be significantly reduced if needed (at the cost of supporting less concurrent flows)
+by using the following link:trex_manual.html#_memory_section_configuration[configuration]
+
+Limitations:
+
+1. Performance is limited. For each NIC port pair, you can utilize only one CPU core.
+2. Using vSwitch will limit the maximum PPS to around 1MPPS.
+3. Latency results will not be accurate.
+
+==== Why not all DPDK supported NICs supported by TRex?
+1. We are using specific NIC features. Not all the NICs have the capabilities we need.
+2. We have regression tests in our lab for each recommended NIC. We do not claim to support NICs we do not have in our lab.
+
+==== Is Cisco VIC supported?
+No. Currently its DPDK driver does not support the capabilities needed to run TRex.
+
+==== Is 100Gbs NIC QSFP+ supported?
+Not yet. Support for FM10K and Mellanox Connectx5 is under development.
+
+==== Is there a GUI?
+TRex team is not developing it. Have a look link:https://groups.google.com/forum/#!searchin/trex-tgn/sari%7Csort:relevance/trex-tgn/R92-N2Yjy2Q/DIUe06YCBgAJ[here] for TRex Stateless mode GUI from Exalt company.
+
+==== What is the maximum number of ports per TRex application?
+12 ports
+
+==== I can not see all 12 ports statistics on TRex server .
+We present statistics only for first four ports because there is no console space. Global statistics (like total TX) is correct, taking into account all ports.
+You can use the GUI/console or Python API, to see statistics for all ports.
+
+==== Can I run multiple TRex servers on the same machine?
+One option for running few instances on the same physical machine is to install few VMs.
+Currently, it is complicated to do without using VMs (but possible with some advanced config file options). We are working on
+a solution to make this easier.
+
+==== Can I use multiple types of ports with the same TRex server instance?
+No. All ports in the configuration file should be of the same NIC type.
+
+==== What is better, running TRex on VM with PCI pass through or TRex on bare metal?
+The answer depends on your budget and needs. Bare metal will have lower latency and better performance. VM has the advantages you normally get when using VMs.
+
+==== I want to report an issue.
+
+You have two options: +
+1. Send email to our support group: trex.tgen@gmail.com +
+2. Open a defect at our link:https://trex-tgn.cisco.com/youtrack[youtrack]. You can also influence by voting in youtrack for an
+existing issue. Issues with lots of voters will probably be fixed sooner.
+
+
+==== I have Intel X710 NIC with 4x10Gb/sec ports and I can not get line rate.
+x710da4fh with 4 10G ports can reach a maximum of 40MPPS (total for all ports) with 64 bytes packets. (can not reach the theoretical 60MPPS limit).
+This is still better than the Intel x520 (82559 based) which can reach ~30MPPS for two ports with one NIC.
+
+==== I have XL710 NIC with 2x40Gb/sec ports and I can not get line rate
+XL710-da2 with 2 40G ports can reach maximum of 40MPPS/50Gb (total for all ports) and not 60MPPS with small packets (64B)
+Intel had in mind redundancy use case when they produced a two port NIC. Card was not intended to reach 80G line rate.
+see link:trex_stateless_bench.html[xl710_benchmark.html] for more info
+
+==== I want to contribute to the project
+You have several ways you can help: +
+1. Download the product, use it, and report issues (If no issues, we will be very happy to also hear success stories). +
+2. If you use the product and have improvment suggestions (for the product or documentation) we will be happy to hear. +
+3. If you fix a bug, or develop new feature, you are more than welcome to create pool request in GitHub.
+
+==== What is the release process? How do I know when a new release is available?
+It is a continuous integration. The latest internal version is under 24/7 regression on few setups in our lab. Once we have enough content we release it to GitHub (Usually every few weeks).
+We do not send an email for every new release, as it could be too frequent for some people. We announce big feature releases on the mailing list. You can always check the GitHub of course.
+
+=== Startup and Installation
+
+==== Can I experiment with TRex without installing?
+You can. Check the TRex sandbox at Cisco devnet in the following link:https://devnetsandbox.cisco.com/RM/Diagram/Index/2ec5952d-8bc5-4096-b327-c294acd9512d?diagramType=Topology[link].
+
+==== How do I obtain TRex, and what kind of hardware do I need?
+You have several options. +
+1. For playing around and experimenting, you can install TRex on VirtualBox by following this link:trex_vm_manual.html[link]. +
+2. To run the real product, check link:trex_manual.html#_download_and_installation[here] for hardware recommendation and
+installation instructions.
+
+==== During OS installation, screen is skewed / error "out of range" / resolution not supported etc.
+
+ * Fedora - during installation, choose "Troubleshooting" -> Install in basic graphic mode.
+ * Ubuntu - try Ubuntu server, which has textual installation.
+
+==== How to determine relation between TRex ports and device under test ports?
+
+Run TRex with the below command and check incoming packet count on DUT interfaces.
+
+[source,bash]
+----
+ sudo ./t-rex-64 -f cap2/dns.yaml --lm 1 --lo -l 1000 -d 100
+----
+
+Alternatively, you can run TRex in stateless mode, send traffic from each port, and look at the counters on the DUT interfaces.
+
+==== How to determine relation between Virtual OS ports and Hypervisor ports?
+
+Compare the MACs address + name of interface, for example:
+
+[source,bash]
+----
+> ifconfig
+eth0 Link encap:Ethernet HWaddr 00:0c:29:2a:99:b2
+ ...
+
+> sudo ./dpdk_setup_ports.py -s
+03:00.0 'VMXNET3 Ethernet Controller' if=eth0 drv=vmxnet3 unused=igb_uio
+----
+
+[NOTE]
+=====================================
+If at TRex side the NICs are not visible to ifconfig, run: +
+....
+sudo ./dpdk_nic_bind.py -b <driver name> <1> <PCI address> <2>
+....
+
+<1> driver name - vmxnet3 for VMXNET3 and e1000 for E1000
+<2> 03:00.0 for example
+
+We are planning to add MACs to `./dpdk_setup_ports.py -s`
+=====================================
+
+==== TRex traffic does not show up on Wireshark, so I can not capture the traffic from the TRex port
+TRex uses DPDK which takes ownership of the ports, so using Wireshark is not possible. You can use switch with port mirroring to capture the traffic.
+
+=== Stateful
+
+==== How do I start using the stateful mode?
+You should first have a YAML configuration file. See link:trex_manual.html#_traffic_yaml_parameter_of_f_option[here].
+Then, you can find some basic examples link:trex_manual.html#_trex_command_line[here].
+
+==== TRex is connected to a switch and I observe many dropped packets at TRex startup.
+A switch might be configured with spanning tree enabled. TRex reset the port at startup, making the switch reset it side as well,
+and spanning tree can drop the packets until it stabilizes.
+Disabling spanning tree can help. On Cisco nexus, you can do that using `spanning-tree port type edge`
+You can also start TRex with -k <num> flag. This will send packets for k seconds before starting the actual test, letting the spanning
+tree time to stabilize.
+This issue will be fixed when we consolidate ``Stateful'' and ``Stateless'' RPC.
+
+==== I can not see any RX packets.
+Most common reason is problems with MAC addresses.
+If your ports are connected in loopback, follow link:trex_manual.html#_configuring_for_loopback[this] carefully. +
+If loopback worked for you, continue link:trex_manual.html#_configuring_for_running_with_router_or_other_l3_device_as_dut[here]. +
+If you set MAC addresses manually in your config file, check again that they are correct. +
+If you have ip and default_gw in your config file, you can debug the initial ARP resolution process by running TRex with
+-d 1 flag (will stop TRex 1 second after init phase, so you can scroll up and look at init stage log), and -v 1.
+This will dump the result of ARP resolution (``dst MAC:...''). You can also try -v 3.
+This will print more debug info, and also ARP packets TX/RX indication and statistics. +
+On the DUT side - If you configured static ARP, verify it is correct. If you depend on TRex gratuitous ARP messages, look at the DUT ARP
+table after TRex init phase and verify its correctness.
+
+==== Why the performance is low?
+
+TRex performance depends on many factors:
+
+1. Make sure trex_cfg.yaml is optimal see "platform" section in manual
+2. More concurrent flows will reduce the performance
+3. Short flows with one/two packets (e.g. cap2/dns.yaml ) will give the worst performance
+
+==== Is there a plan to add TCP stack?
+Yes. We know this is something many people would like, and are working on this. No ETA yet. Once a progress is made, we will announce it on the TRex site and mailing list.
+
+==== How can I run the YAML profile and capture the results to a pcap file?
+You can use the simulator. see link:trex_manual.html#_simulator[simulator]
+The output of the simulator can be loaded to Excel. The CPS can be tuned.
+
+==== I want to have more acrive flows in TRex, how can I do this?
+Default maximum supported flows is 1M (From TRex prespective. DUT might have much more due to slower aging). When active flows reach higher number, you will get ``out of memory'' error message
+
+To increase the number of supported active flows, you should add ``dp_flows'' arg in config file ``memory'' section.
+Look link:trex_manual.html#_memory_section_configuration[here] for more info.
+
+==== I want to have more active flows on the DUT, how can I do this?
+After stretching TRex to its maximum CPS capacity, consider the following: DUT will have much more active flows in case of a UDP flow due to the nature of aging (DUT does not know when the flow ends while TRex knows).
+In order to artificialy increse the length of the active flows in TRex, you can config larger IPG in the YAML file. This will cause each flow to last longer. Alternatively, you can increase IPG in your PCAP file as well.
+
+==== I am getting an error: The number of ips should be at least number of threads.
+The range of clients and servers should be at least the number of threads.
+The number of threads is equal to (number of port pairs) * (-c value)
+
+==== Some of the incoming frames are of type SCTP. Why?
+Default latency packets are SCTP, you can omit the `-l <num>` from command line, or change it to ICMP. See the manual for more info.
+
+=== Stateless
+
+==== How do I get started with stateless mode?
+You should first have a YAML configuration file. See link:trex_manual.html#_traffic_yaml_parameter_of_f_option[here].
+Then, you can have a look at the stateless manual link:trex_stateless.html[here]. You can jump right into the link:trex_stateless.html#_tutorials[tutorials section].
+
+==== Is pyATS supported as client framework
+
+Yes. Both Python 3 and Python 2
+
+==== Python API does not work on my Mac with the below ZMQ library issue
+
+We are using Python ZMQ wrapper. It needs to be compiled per platform and we have a support for many platforms but not all of them.
+You will need to build ZMQ for your platform if it is not part of the package.
+
+[source,Python]
+----
+ from .trex_stl_client import STLClient, LoggerApi
+ File "../trex_stl_lib/trex_stl_client.py", line 7, in <module>
+ from .trex_stl_jsonrpc_client import JsonRpcClient, BatchMessage
+ File "../trex_stl_lib/trex_stl_jsonrpc_client.py", line 3, in <module>
+ import zmq
+ File "/home/shilwu/trex_client/external_libs/pyzmq-14.5.0/python2/fedora18/64bit/zmq/__init__.py", line 32, in <module>
+ _libzmq = ctypes.CDLL(bundled[0], mode=ctypes.RTLD_GLOBAL)
+ File "/usr/local/lib/python2.7/ctypes/__init__.py", line 365, in __init__
+ self._handle = _dlopen(self._name, mode)
+OSError: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /home/shilwu/trex_client/external_libs/pyzmq-14.5.0/python2/fedora18/64bit/zmq/libzmq.so.3)
+
+----
+
+
+==== Is multi-user supported
+
+Yes. Multiple TRex clients can connect to the same TRex server.
+
+==== Can I create corrupted packets?
+
+Yes. You can build any packet you like using Scapy.
+However, there is no way to create corrupted L1 fields (Like Ethernet FCS), since these are usually handled by the NIC hardware.
+
+==== Why the performance is low?
+Major things that can reduce the performance are:
+
+1. Many concurent streams.
+2. Complex field engine program.
+
+Adding ``cache'' directive can improve the performance. See link:trex_stateless.html#_tutorial_field_engine_significantly_improve_performance[here]
+
+and try this:
+
+[source,bash]
+----
+$start -f stl/udp_1pkt_src_ip_split.py -m 100%
+----
+
+[source,python]
+----
+
+ vm = STLScVmRaw( [ STLVmFlowVar ( "ip_src",
+ min_value="10.0.0.1",
+ max_value="10.0.0.255",
+ size=4, step=1,op="inc"),
+
+ STLVmWrFlowVar (fv_name="ip_src",
+ pkt_offset= "IP.src" ),
+
+ STLVmFixIpv4(offset = "IP")
+ ],
+ split_by_field = "ip_src",
+ cache_size =255 # the cache size <1>
+ );
+----
+<1> cache
+
+
+==== I want to generate gratuitous ARP/NS IPv6.
+
+See example link:trex_stateless.html#_tutorial_field_engine_many_clients_with_arp[here]
+
+==== How do I create deterministic random stream variable?
+
+use `random_seed` per stream
+
+[source,python]
+----
+ return STLStream(packet = pkt,
+ random_seed = 0x1234,
+ mode = STLTXCont())
+----
+
+==== Can I have a synconization betwean different stream variables?
+
+No. each stream has its own, seperate field engine program.
+
+
+==== Is there a plan to have LUAJit as a field engine program?
+
+It is a great idea to add it, we are looking for someone to contribute this support.
+
+==== Java API instead of Python API
+
+Q:: I want to use the Python API via Java (with Jython), apparently, I can not import Scapy modules with Jython.
+The way I see it I have two options:
+
+1. Creating python scripts and call them from java (with ProcessBuilder for example)
+2. Call directly to the TRex server over RPC from Java
+
+However, option 2 seems like a re-writing the API for Java (which I am not going to do)
+On the other hand, with option 1, once the script is done, the client object destroyed and I cannot use it anymore in my tests.
+
+Any ideas on what is the best way to use TRex within JAVA?
+
+A::
+
+The power of our Python API is the scapy integration for simple building of the packets and the field engine.
+There is a proxy over RPC that you can extend to your use cases. It has basic functionality, like connect/start/stop/get_stats.
+You could use it to send some pcap file via ports, or so-called python profiles, which you can configure by passing different variables (so-called tunabels) via the RPC.
+Take a look at link:trex_stateless.html#_using_stateless_client_via_json_rpc[using_stateless_client_via_json_rpc].
+You can even dump the profile as a string and move it to the proxy to run it (Notice that it is a potential security hole, as you allow outside content to run as root on the TRex server).
+
+See link:https://github.com/zverevalexei/trex-http-proxy[here] an example for simple Web server proxy for interacting with TRex.
+
+==== Where can I find a reference to RFC2544 using TRex
+
+link:https://gerrit.fd.io/r/gitweb?p=csit.git;a=tree;f=resources;hb=HEAD[here]
+
+
+==== Are you recommending TRex HLTAPI ?
+TRex has minimal and basic support for HLTAPI. For simple use cases (without latency and per stream statistic) it will probably work. For advanced use cases, there is no replacement for native API that has full control and in most cases is simpler to use.
+
+==== Can I test Qos using TRex ?
+Yes. Using Field Engine you can build streams with different TOS and get statistic/latency/jitter per stream
+
+==== What are the supported routing protocols TRex can emulate?
+For now, none. You can connect your router to a switch with TRex and a machine running routem. Then, inject routes using routem, and other traffic using TRex.
+
+==== Latency and per stream statistics
+===== Does latency stream support full line rate?
+No. latency streams are handled by rx software and there is only one core to handle the traffic.
+To workaround this you could create one stream in lower speed for latency (e.g. PPS=1K) and another one of the same type without latency. The latency stream will sample the DUT queues. For example, if the required latency resolution is 10usec there is no need to send a latency stream in speed higher than 100KPPS- usually queues are built over time, so it is not possible that one packet will have a latency and another packet in the same path will not have the same latency. The none latency stream could be in full line rate (e.g. 100MPPS)
+
+.Example
+[source,Python]
+--------
+ stream = [STLStream(packet = pkt,
+ mode = STLTXCont(pps=1)), <1>
+
+
+ # latency stream
+ STLStream(packet = pkt,
+ mode = STLTXCont(pps=1000), <2>
+ flow_stats = STLFlowLatencyStats(pg_id = 12+port_id))
+--------
+<1> non latency stream will be amplified
+<2> latency stream, the speed will be constant 1KPPS
+
+
+===== Latency stream has constant rate of 1PPS, and is not getting amplified by multiplier. Why?
+Reason for this (besides being a CPU constrained feature) is that most of the time, the use case is that you load the DUT using some traffic streams, and check latency
+using different streams. The latency stream is kind of ``testing probe'' which you want to keep at constant rate, while playing with the rate of your other (loading) streams.
+So, you can use the multiplier to amplify your main traffic, without changing your ``testing probe''.
+
+When you have the following example:
+
+[source,Python]
+--------
+ stream = [STLStream(packet = pkt,
+ mode = STLTXCont(pps=1)), <1>
+
+
+ # latency stream
+ STLStream(packet = STLPktBuilder(pkt = base_pkt/pad_latency),
+ mode = STLTXCont(pps=1000), <2>
+ flow_stats = STLFlowLatencyStats(pg_id = 12+port_id))
+--------
+<1> non latency stream
+<2> latency stream
+
+
+If you speicify a multiplier of 10KPPS in start API, the latency stream (#2) will keep the rate of 1000 PPS and will not be amplified.
+
+If you do want to amplify latency streams, you can do this using ``tunables''.
+You can add in the Python profile a ``tunable'' which will specify the latency stream rate and you can provide it to the ``start'' command in the console or in the API.
+Tunables can be added through the console using ``start ... -t latency_rate=XXXXX''
+or using the Python API directly (for automation):
+STLProfile.load_py(..., latency_rate = XXXXX)
+You can see example for defining and using tunables link:trex_stateless.html#_tutorial_advanced_traffic_profile[here].
+
+
+===== Latency and per stream statistics are not supported for all packet types.
+
+Correct. We use NIC capabilities for counting the packets or directing them to be handled by software. Each NIC has its own capabilities. Look link:trex_stateless.html#_tutorial_per_stream_statistics[here] for per stream statistics and link:trex_stateless.html#_tutorial_per_stream_latency_jitter_packet_errors[here] for latency details.
+
+
+
+
+
diff --git a/doc/trex_ga.asciidoc b/doc/trex_ga.asciidoc
new file mode 100755
index 00000000..f5db320f
--- /dev/null
+++ b/doc/trex_ga.asciidoc
@@ -0,0 +1,17 @@
+
+ifdef::backend-xhtml11[]
+++++
+<script>
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', 'UA-75220362-1', 'auto');
+ ga('send', 'pageview');
+
+</script>
+++++
+endif::backend-xhtml11[]
+
+
diff --git a/doc/trex_index.asciidoc b/doc/trex_index.asciidoc
new file mode 100644
index 00000000..454e21ec
--- /dev/null
+++ b/doc/trex_index.asciidoc
@@ -0,0 +1,104 @@
+TRex Documentation
+==================
+:quotes.++:
+:web_server_url: https://trex-tgn.cisco.com/trex
+:local_web_server_url: csi-wiki-01:8181/trex
+:toclevels: 4
+
+include::trex_ga.asciidoc[]
+
+== Presentations
+
+[options="header",cols="<4,a"]
+|=================
+| Description | Name
+| Stateful |
+link:trex_preso.html[Stateful]
+| Stateful DPDK |
+link:http://www.slideshare.net/harryvanhaaren/trex-traffig-gen-hanoch-haim[DPDK summit]
+| *New* Stateless support |
+http://www.slideshare.net/HanochHaim/trex-realistic-traffic-generator-stateless-support[Stateless support]
+|=================
+
+
+== User Guides
+
+[options="header",cols="<4,a"]
+|=================
+| Description | Name
+| FAQ |
+link:trex_faq.html[FAQ]
+| Installation Guide |
+link:trex_manual.html#_download_and_installation[Installation]
+| Release Notes |
+link:release_notes.html[Release_notes.html]
+| Stateful Manual and Getting Started |
+link:trex_manual.html[trex_manual.html] link:trex_book.pdf[trex_manual.pdf]
+| Stateless Manual |
+link:trex_stateless.html[trex_stateless.html] link:trex_stateless.pdf[trex_stateless.pdf]
+| Tutorial TRex on VirtualBox |
+link:trex_vm_manual.html[trex_vm_manual.html] link:trex_vm_manual.pdf[trex_vm_manual.pdf]
+| Cisco Devnet SandBox |
+link:https://devnetsandbox.cisco.com/RM/Diagram/Index/2ec5952d-8bc5-4096-b327-c294acd9512d?diagramType=Topology[Sandbox] link:https://developer.cisco.com/site/trex/[Devnet site& sandbox]
+|=================
+
+== Python Automation API
+
+[options="header",cols="<4,a"]
+|=================
+| Description | Name
+| Stateless Python automation API |
+link:cp_stl_docs/index.html[stateless_sdk]
+| Stateful Python automation API |
+link:cp_docs/index.html[statelful_sdk]
+| Stateful API tutorial |
+link:trex_control_plane_peek.html[Stateful API]
+| Stateless API tutorial |
+See Stateless Manual
+|=================
+
+== Miscellaneous
+
+[options="header",cols="<4,a"]
+|=================
+| Description | Name
+| GitHub |
+link:https://github.com/cisco-system-traffic-generator/trex-core[GitHub]
+| Wiki |
+link:https://github.com/cisco-system-traffic-generator/trex-core/wiki[Wiki]
+| Defect manager |
+link:http://trex-tgn.cisco.com/youtrack/dashboard[youtrack]
+| Release pkgs |
+link:../release/[pkgs]
+| Windows Stateful GUI |
+link:../client_gui/[stateful GUI]
+| XL710 Statless performance |
+link:trex_stateless_bench.html[xl710_benchmark.html]
+|=================
+
+== For Developers
+
+[options="header",cols="<4,a"]
+|=================
+| Description | Name
+| Stateless server RPC specification |
+link:trex_rpc_server_spec.html[stl_rpc_server.html]
+| Scapy server RPC specification |
+link:trex_scapy_rpc_server.html[scapy_rpc_spec.html]
+| How to build |
+link:https://github.com/cisco-system-traffic-generator/trex-core/wiki[Wiki]
+|=================
+
+== Support
+
+[options="header",cols="<4,a"]
+|=================
+| Description | Name
+| TRex community |
+link:https://groups.google.com/forum/#!forum/trex-tgn[Gmail TRex Forum]
+| Report a defect |
+link:http://trex-tgn.cisco.com/youtrack/dashboard[youtrack]
+| Cisco TRex Devnet community |
+link:https://communities.cisco.com/community/developer/trex[Jive]
+|=================
+
diff --git a/doc/trex_preso.asciidoc b/doc/trex_preso.asciidoc
new file mode 100755
index 00000000..46ec91f8
--- /dev/null
+++ b/doc/trex_preso.asciidoc
@@ -0,0 +1,1326 @@
+TRex realistic traffic generator
+================================
+:author: hhaim
+:email: <hhaim@cisco.com>
+:description: TRex Low cost, High scale, realistic traffic generator
+:revdate: 2014-11-01
+:revnumber: 0.2
+:deckjs_theme: swiss
+:deckjs_transition: horizontal-slide
+:scrollable:
+:web_server_url: https://trex-tgn.cisco.com/trex
+
+
+include::trex_ga.asciidoc[]
+
+
+== What problem is being solved?
+
+* Network elements include complex stateful features
+* Require testing with stateful and real traffic mix
+* Traffic generators of stateful/realistic traffic are:
+** Expensive ~$100-500K
+** Not scalable for high rates
+** Not flexible
+* Due to cost, quality is impacted
+** Limited access / testing
+** Late testing
+** No standard
+
+++++++++++++++++++
+<script type="text/javascript"
+ src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
+</script>
+
+<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+
+<script src="my_chart.js"></script>
+
+<style>
+.axis path,
+.axis line {
+ fill: none;
+ stroke: #000;
+ shape-rendering: crispEdges;
+}
+
+.dot {
+ stroke: #000;
+}
+</style>
+
+
+<style type="text/css">
+
+h1 {
+ font-size: 2.5em;
+}
+
+h2 {
+ font-size: 1.5em;
+ color: #CD7300;
+ border-bottom-color: #000;
+}
+
+h7 {
+ font-size: 4.5em;
+ color: #CD7300;
+ position: relative;
+ top: auto;
+ text-align: center;
+ padding: 0;
+ -webkit-transform: none;
+ -moz-transform: none;
+ -ms-transform: none;
+ -o-transform: none;
+ transform: none;
+ padding: 0 48px;
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 50%;
+}
+
+h8 {
+ font-size: 2.25em;
+ font-weight: bold;
+ padding-top: .5em;
+ margin: 0 0 .66666em 0;
+ border-top: 3px solid #888;
+ color: #c00;
+ border-top-color: #ccc;
+ left: 0;
+ right: 0;
+ top: 40%;
+}
+
+
+html, body {
+ height: 100%;
+ margin: 0 auto;
+ max-width: 1000px;
+}
+
+</style>
+
+<script>
+ $('#title-slide').css("background-image", "url('images/trex_logo.png')");
+ $('#title-slide').css("background-repeat","no-repeat");
+ $('#title-slide').css("background-position","center");
+ $('h1').html('');
+ $('h3').html('<font size="4">Hanoch Haim v1.2</font>');
+ $('h4').html('<font size="4">04/2015</font>');
+ $('h5').html('<font size="4">Updated 10/2016</font>');
+ </script>
+
+<script>
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', 'UA-75220362-1', 'auto');
+ ga('send', 'pageview');
+
+</script>
+
+++++++++++++++++++
+
+
+== What is TRex?
+
+
+* TRex is a *statefull* *traffic* *generator* tool based on a smart replay of real flows (not a full TCP/IP stack,yet)
+++++++++++++++++++
+<img src="images/ucs200_2.png" alt="title=" align="right" >
+++++++++++++++++++
+* Generates, manipulates and amplifies based on templates of a real/captured flows.
+* Templates are processed offline
+* *High* *performance* full line rate
+** tx= up to 200Gb/sec rx=up to 200Gb/sec
+* *Low* *cost* C220M UCS-1RU, Cisco internal eqip
+* Generate both sides of the traffic Clients and Servers
+* *Standard* *hardware* (X86/Intel NIC I350,82599,XL710)
+++++++++++++++++++
+<img src="images/Intel520.png" alt="title=" align="right" >
+++++++++++++++++++
+* Flexible and Open Software (DPDK)
+* Support Virtualization
+* Virtual interface support *E1000* , *VMXNET3*. Enabler for
+** Amazon AWS
+** Cisco LaaS
+
+== Realistic traffic model
+
+++++++++++++++++++
+<img src="images/trex_model.png" alt="title=" align="center" >
+++++++++++++++++++
+
+== TRex high level software architecture
+
+++++++++++++++++++
+<img src="images/trex_desing.png" alt="title=" align="right" >
+++++++++++++++++++
+
+* *DPDK*
+** user space driver
+** Big TLB
+** Utilize all DDR banks
+
+* *Multi-Threaded*
+** Scale linearly
+** ~20Gb/sec per DP core
+
+* *No TCP-IP*
+** Fast events scheduler
+** Generate flows template
+** Can support 1K templates
+
+* *Slow-path flexibility (per-flow)*
+** Client/server generation
+** Measure latency
+** Measure flow order
+** NAT translation learning
+
+== TRex basic flows generation algorithm
+
+++++++++++++++++++
+<img src="images/trex_algo.png" alt="title=" align="center" >
+++++++++++++++++++
+
+== DNS simple profile example
+
+* traffic profile is in YAML fomat
+
+[source,python]
+----
+$more cap2/dns_test.yaml
+- duration : 10.0
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.0.255"
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 1
+ udp_aging : 1
+ cap_info :
+ - name: cap2/dns.pcap <1>
+ cps : 1.0 <2>
+----
+<1> the pcap file that include DNS cap file that will be replicate
+<2> how many connection per second to generate, 1.0 means 1 connection per secod
+
+image:images/dns_wireshark.png[title="generator"]
+
+== DNS simple profile output
+
+.Formated results
+[format="csv",cols="1^,2^,1^,1^,2^,1^,2^,1^", options="header"]
+|=================
+ pkt,time sec,fid,flow-pkt-id,client_ip,client_port,server_ip ,direction
+ 1 , 0.010000 , 1 , 1 , 16.0.0.1 , 1024 , 48.0.0.1 , ->
+ 2 , 0.020000 , 1 , 2 , 16.0.0.1 , 1024 , 48.0.0.1 , <-
+ 3 , 2.010000 , 2 , 1 , 16.0.0.2 , 1024 , 48.0.0.2 , ->
+ 4 , 2.020000 , 2 , 2 , 16.0.0.2 , 1024 , 48.0.0.2 , <-
+ 5 , 3.010000 , 3 , 1 , 16.0.0.3 , 1024 , 48.0.0.3 , ->
+ 6 , 3.020000 , 3 , 2 , 16.0.0.3 , 1024 , 48.0.0.3 , <-
+ 7 , 4.010000 , 4 , 1 , 16.0.0.4 , 1024 , 48.0.0.4 , ->
+ 8 , 4.020000 , 4 , 2 , 16.0.0.4 , 1024 , 48.0.0.4 , <-
+ 9 , 5.010000 , 5 , 1 , 16.0.0.5 , 1024 , 48.0.0.5 , ->
+ 10 , 5.020000 , 5 , 2 , 16.0.0.5 , 1024 , 48.0.0.5 , <-
+ 11 , 6.010000 , 6 , 1 , 16.0.0.6 , 1024 , 48.0.0.6 , ->
+|=================
+
+== DNS simple profile chart
+
+
++++++++++++++++++++++++++++++++++
+<div id="chart1" style="font : 10px sans-serif"; ></div>
+
+<script>
+var dns_data=[
+[ 0.010000 , 1 , 0 , 1 ],
+[ 0.060000 , 1 , 0 , 2 ],
+[ 0.210000 , 2 , 0 , 1 ],
+[ 0.260000 , 2 , 0 , 2 ],
+[ 0.310000 , 3 , 0 , 1 ],
+[ 0.360000 , 3 , 0 , 2 ],
+[ 0.410000 , 4 , 0 , 1 ],
+[ 0.460000 , 4 , 0 , 2 ],
+[ 0.510000 , 5 , 0 , 1 ],
+[ 0.560000 , 5 , 0 , 2 ],
+[ 0.610000 , 6 , 0 , 1 ],
+[ 0.660000 , 6 , 0 , 2 ],
+[ 0.710000 , 7 , 0 , 1 ],
+[ 0.760000 , 7 , 0 , 2 ],
+[ 0.810000 , 8 , 0 , 1 ],
+[ 0.860000 , 8 , 0 , 2 ],
+[ 0.910000 , 9 , 0 , 1 ],
+[ 0.960000 , 9 , 0 , 2 ],
+[ 1.010000 , 10 , 0 , 1 ],
+[ 1.060000 , 10 , 0 , 2 ],
+];
+chart("#chart1",dns_data,["dns"],"time-sec","flow-id");
+</script>
+
++++++++++++++++++++++++++++++++++
+
+== HTTP & DNS profile example
+
+[source,python]
+----
+- duration : 1.0
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.0.10"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.0.3"
+ dual_port_mask : "1.0.0.0"
+ tcp_aging : 1
+ udp_aging : 1
+ cap_ipg : true
+ cap_info :
+ - name: cap2/dns.pcap
+ cps : 10.0 <1>
+ - name: avl/delay_10_http_browsing_0.pcap
+ cps : 2.0 <1>
+----
+<1> Diffrent CPS
+
+* Inter packet Gap (IPG) is taken from pcap file
+* IPG can be manualy set
+
+== HTTP & DNS profile chart
+
++++++++++++++++++++++++++++++++++
+<div id="chart3" style="font : 10px sans-serif"; ></div>
+
+<script>
+var chart3_data=[
+[ 0.010000 , 1 , 0 , 1 ],
+[ 0.030944 , 1 , 0 , 2 ],
+[ 0.093333 , 2 , 1 , 1 ],
+[ 0.104362 , 2 , 1 , 2 ],
+[ 0.115385 , 2 , 1 , 3 ],
+[ 0.115394 , 2 , 1 , 4 ],
+[ 0.126471 , 2 , 1 , 5 ],
+[ 0.126484 , 2 , 1 , 6 ],
+[ 0.137530 , 2 , 1 , 7 ],
+[ 0.148609 , 2 , 1 , 8 ],
+[ 0.148621 , 2 , 1 , 9 ],
+[ 0.148635 , 2 , 1 , 10 ],
+[ 0.159663 , 2 , 1 , 11 ],
+[ 0.170750 , 2 , 1 , 12 ],
+[ 0.170762 , 2 , 1 , 13 ],
+[ 0.170774 , 2 , 1 , 14 ],
+[ 0.176667 , 3 , 0 , 1 ],
+[ 0.181805 , 2 , 1 , 15 ],
+[ 0.181815 , 2 , 1 , 16 ],
+[ 0.192889 , 2 , 1 , 17 ],
+[ 0.192902 , 2 , 1 , 18 ],
+[ 0.192914 , 2 , 1 , 19 ],
+[ 0.192927 , 2 , 1 , 20 ],
+[ 0.192939 , 2 , 1 , 21 ],
+[ 0.192951 , 2 , 1 , 22 ],
+[ 0.197611 , 3 , 0 , 2 ],
+[ 0.203944 , 2 , 1 , 23 ],
+[ 0.203950 , 2 , 1 , 24 ],
+[ 0.203956 , 2 , 1 , 25 ],
+[ 0.214620 , 2 , 1 , 26 ],
+[ 0.214633 , 2 , 1 , 27 ],
+[ 0.214645 , 2 , 1 , 28 ],
+[ 0.214658 , 2 , 1 , 29 ],
+[ 0.214671 , 2 , 1 , 30 ],
+[ 0.214682 , 2 , 1 , 31 ],
+[ 0.214695 , 2 , 1 , 32 ],
+[ 0.214707 , 2 , 1 , 33 ],
+[ 0.225264 , 2 , 1 , 34 ],
+[ 0.225269 , 2 , 1 , 35 ],
+[ 0.225274 , 2 , 1 , 36 ],
+[ 0.225279 , 2 , 1 , 37 ],
+[ 0.260000 , 4 , 0 , 1 ],
+[ 0.280944 , 4 , 0 , 2 ],
+[ 0.343333 , 5 , 0 , 1 ],
+[ 0.364277 , 5 , 0 , 2 ],
+[ 0.426667 , 6 , 0 , 1 ],
+[ 0.447611 , 6 , 0 , 2 ],
+[ 0.593333 , 7 , 0 , 1 ],
+[ 0.614277 , 7 , 0 , 2 ],
+[ 0.676667 , 8 , 1 , 1 ],
+[ 0.687696 , 8 , 1 , 2 ],
+[ 0.698719 , 8 , 1 , 3 ],
+[ 0.698728 , 8 , 1 , 4 ],
+[ 0.709805 , 8 , 1 , 5 ],
+[ 0.709818 , 8 , 1 , 6 ],
+[ 0.720864 , 8 , 1 , 7 ],
+[ 0.731943 , 8 , 1 , 8 ],
+[ 0.731955 , 8 , 1 , 9 ],
+[ 0.731968 , 8 , 1 , 10 ],
+[ 0.742997 , 8 , 1 , 11 ],
+[ 0.754084 , 8 , 1 , 12 ],
+[ 0.754096 , 8 , 1 , 13 ],
+[ 0.754108 , 8 , 1 , 14 ],
+[ 0.760000 , 9 , 0 , 1 ],
+[ 0.765139 , 8 , 1 , 15 ],
+[ 0.765148 , 8 , 1 , 16 ],
+[ 0.776223 , 8 , 1 , 17 ],
+[ 0.776236 , 8 , 1 , 18 ],
+[ 0.776248 , 8 , 1 , 19 ],
+[ 0.776261 , 8 , 1 , 20 ],
+[ 0.776273 , 8 , 1 , 21 ],
+[ 0.776285 , 8 , 1 , 22 ],
+[ 0.780944 , 9 , 0 , 2 ],
+[ 0.787278 , 8 , 1 , 23 ],
+[ 0.787284 , 8 , 1 , 24 ],
+[ 0.787289 , 8 , 1 , 25 ],
+[ 0.797954 , 8 , 1 , 26 ],
+[ 0.797967 , 8 , 1 , 27 ],
+[ 0.797979 , 8 , 1 , 28 ],
+[ 0.797992 , 8 , 1 , 29 ],
+[ 0.798004 , 8 , 1 , 30 ],
+[ 0.798016 , 8 , 1 , 31 ],
+[ 0.798029 , 8 , 1 , 32 ],
+[ 0.798041 , 8 , 1 , 33 ],
+[ 0.808598 , 8 , 1 , 34 ],
+[ 0.808603 , 8 , 1 , 35 ],
+[ 0.808608 , 8 , 1 , 36 ],
+[ 0.808613 , 8 , 1 , 37 ],
+[ 0.843333 , 10 , 0 , 1 ],
+[ 0.864277 , 10 , 0 , 2 ],
+[ 0.926667 , 11 , 0 , 1 ],
+[ 0.947611 , 11 , 0 , 2 ],
+[ 1.010000 , 12 , 0 , 1 ],
+[ 1.030944 , 12 , 0 , 2 ],
+];
+chart("#chart3",chart3_data,["dns","http"],"time-sec","flow-id");
+</script>
++++++++++++++++++++++++++++++++++
+
+== EMIX traffic profile
+
+++++++++++++++++++
+<img src="images/trex_sfr_profile.png" alt="title=" align="right" >
+++++++++++++++++++
+
+* EMIX traffic profile suggested. used for NBAR/AVC tests
+* Property
+** BW: 70% TCP (http, mail) , 30% UDP (rtp)
+** Connections: 50% TCP (http, mail) , 50% UDP (rtp, dns)
+** Avg. Packet Size (~585B)
+** PPS= 221K per 1Gb/sec
+** CPS = 4K per 1Gb/sec
+** Flows per 1Gb/sec = 50K
+** Avg. Packets per flow (50)
+
+== EMIX YAML profile
+
+.Simplified version of EMIX YAML profile
+[source,python]
+----
+- duration : 0.1
+ generator :
+ distribution : "seq"
+ clients_start : "16.0.0.1"
+ clients_end : "16.0.1.255"
+ servers_start : "48.0.0.1"
+ servers_end : "48.0.20.255"
+ dual_port_mask : "1.0.0.0"
+ cap_ipg : true
+ cap_info :
+ - name: avl/delay_10_http_get_0.pcap
+ cps : 404.52
+ - name: avl/delay_10_http_post_0.pcap
+ cps : 404.52
+ - name: avl/delay_10_https_0.pcap
+ cps : 130.8745
+ - name: avl/delay_10_http_browsing_0.pcap
+ cps : 709.89
+ - name: avl/delay_10_exchange_0.pcap
+ cps : 253.81
+ - name: avl/delay_10_mail_pop_2.pcap
+ cps : 4.759
+ - name: avl/delay_10_oracle_0.pcap
+ cps : 79.3178
+ - name: avl/delay_10_rtp_160k_full.pcap
+ cps : 2.776
+ - name: avl/delay_10_smtp_0.pcap
+ cps : 7.3369
+ - name: avl/delay_10_sip_video_call_full.pcap
+ cps : 29.347
+ - name: avl/delay_10_citrix_0.pcap
+ cps : 43.6248
+ - name: avl/delay_10_dns_0.pcap
+ cps : 1975.015
+----
+
+== EMIX profile chart
+
++++++++++++++++++++++++++++++++++
+<div id="chart4" style="font : 10px sans-serif"; ></div>
+
+<script>
+
+var sfr_data=[
+[ 0.010000 , 1 , 0 , 1 ],
+[ 0.010245 , 2 , 1 , 1 ],
+[ 0.010490 , 3 , 2 , 1 ],
+[ 0.010735 , 4 , 3 , 1 ],
+[ 0.010979 , 5 , 4 , 1 ],
+[ 0.011224 , 6 , 5 , 1 ],
+[ 0.011469 , 7 , 6 , 1 ],
+[ 0.011714 , 8 , 7 , 1 ],
+[ 0.011959 , 9 , 8 , 1 ],
+[ 0.012204 , 10 , 9 , 1 ],
+[ 0.012449 , 11 , 10 , 1 ],
+[ 0.012694 , 12 , 11 , 1 ],
+[ 0.012938 , 13 , 12 , 1 ],
+[ 0.013183 , 14 , 13 , 1 ],
+[ 0.013428 , 15 , 14 , 1 ],
+[ 0.013673 , 16 , 15 , 1 ],
+[ 0.013918 , 17 , 16 , 1 ],
+[ 0.014163 , 18 , 17 , 1 ],
+[ 0.014408 , 19 , 0 , 1 ],
+[ 0.014652 , 20 , 1 , 1 ],
+[ 0.014897 , 21 , 3 , 1 ],
+[ 0.015142 , 22 , 4 , 1 ],
+[ 0.015387 , 23 , 17 , 1 ],
+[ 0.015632 , 24 , 0 , 1 ],
+[ 0.015877 , 25 , 1 , 1 ],
+[ 0.016122 , 26 , 3 , 1 ],
+[ 0.016367 , 27 , 17 , 1 ],
+[ 0.016611 , 28 , 3 , 1 ],
+[ 0.016856 , 29 , 17 , 1 ],
+[ 0.017101 , 30 , 3 , 1 ],
+[ 0.017346 , 31 , 17 , 1 ],
+[ 0.017591 , 32 , 0 , 1 ],
+[ 0.017836 , 33 , 1 , 1 ],
+[ 0.018081 , 34 , 3 , 1 ],
+[ 0.018325 , 35 , 17 , 1 ],
+[ 0.018456 , 15 , 14 , 2 ],
+[ 0.018570 , 36 , 2 , 1 ],
+[ 0.018815 , 37 , 17 , 1 ],
+[ 0.019060 , 38 , 4 , 1 ],
+[ 0.019305 , 39 , 17 , 1 ],
+[ 0.019550 , 40 , 3 , 1 ],
+[ 0.019795 , 41 , 17 , 1 ],
+[ 0.021137 , 1 , 0 , 2 ],
+[ 0.021294 , 2 , 1 , 2 ],
+[ 0.021534 , 3 , 2 , 2 ],
+[ 0.021764 , 4 , 3 , 2 ],
+[ 0.022007 , 5 , 4 , 2 ],
+[ 0.022251 , 6 , 5 , 2 ],
+[ 0.022505 , 7 , 6 , 2 ],
+[ 0.022768 , 8 , 7 , 2 ],
+[ 0.022989 , 9 , 8 , 2 ],
+[ 0.023245 , 10 , 9 , 2 ],
+[ 0.023490 , 11 , 10 , 2 ],
+[ 0.023747 , 12 , 11 , 2 ],
+[ 0.023963 , 13 , 12 , 2 ],
+[ 0.024212 , 14 , 13 , 2 ],
+[ 0.024972 , 17 , 16 , 2 ],
+[ 0.025262 , 18 , 17 , 2 ],
+[ 0.025545 , 19 , 0 , 2 ],
+[ 0.025701 , 20 , 1 , 2 ],
+[ 0.025926 , 21 , 3 , 2 ],
+[ 0.026169 , 22 , 4 , 2 ],
+[ 0.026486 , 23 , 17 , 2 ],
+[ 0.026769 , 24 , 0 , 2 ],
+[ 0.026926 , 25 , 1 , 2 ],
+[ 0.027151 , 26 , 3 , 2 ],
+[ 0.027465 , 27 , 17 , 2 ],
+[ 0.027640 , 28 , 3 , 2 ],
+[ 0.027955 , 29 , 17 , 2 ],
+[ 0.028130 , 30 , 3 , 2 ],
+[ 0.028445 , 31 , 17 , 2 ],
+[ 0.028728 , 32 , 0 , 2 ],
+[ 0.028885 , 33 , 1 , 2 ],
+[ 0.029110 , 34 , 3 , 2 ],
+[ 0.029424 , 35 , 17 , 2 ],
+[ 0.029614 , 36 , 2 , 2 ],
+[ 0.029914 , 37 , 17 , 2 ],
+[ 0.030087 , 38 , 4 , 2 ],
+[ 0.030404 , 39 , 17 , 2 ],
+[ 0.030579 , 40 , 3 , 2 ],
+[ 0.030894 , 41 , 17 , 2 ],
+[ 0.032188 , 1 , 0 , 3 ],
+[ 0.032197 , 1 , 0 , 4 ],
+[ 0.032341 , 2 , 1 , 3 ],
+[ 0.032367 , 2 , 1 , 4 ],
+[ 0.032379 , 2 , 1 , 5 ],
+[ 0.032576 , 3 , 2 , 3 ],
+[ 0.032583 , 3 , 2 , 4 ],
+[ 0.032787 , 4 , 3 , 3 ],
+[ 0.032796 , 4 , 3 , 4 ],
+[ 0.032931 , 16 , 15 , 2 ],
+[ 0.033031 , 5 , 4 , 3 ],
+[ 0.033052 , 5 , 4 , 4 ],
+[ 0.033065 , 5 , 4 , 5 ],
+[ 0.033272 , 6 , 5 , 3 ],
+[ 0.033460 , 15 , 14 , 3 ],
+[ 0.033527 , 7 , 6 , 3 ],
+[ 0.033802 , 8 , 7 , 3 ],
+[ 0.034029 , 9 , 8 , 3 ],
+[ 0.034280 , 10 , 9 , 3 ],
+[ 0.034288 , 10 , 9 , 4 ],
+[ 0.034525 , 11 , 10 , 3 ],
+[ 0.034533 , 11 , 10 , 4 ],
+[ 0.034797 , 12 , 11 , 3 ],
+[ 0.034989 , 13 , 12 , 3 ],
+[ 0.035271 , 14 , 13 , 3 ],
+[ 0.036008 , 17 , 16 , 3 ],
+[ 0.036442 , 16 , 15 , 3 ],
+[ 0.036596 , 19 , 0 , 3 ],
+[ 0.036605 , 19 , 0 , 4 ],
+[ 0.036749 , 20 , 1 , 3 ],
+[ 0.036775 , 20 , 1 , 4 ],
+[ 0.036787 , 20 , 1 , 5 ],
+[ 0.036949 , 21 , 3 , 3 ],
+[ 0.036958 , 21 , 3 , 4 ],
+[ 0.037193 , 22 , 4 , 3 ],
+[ 0.037215 , 22 , 4 , 4 ],
+[ 0.037227 , 22 , 4 , 5 ],
+[ 0.037820 , 24 , 0 , 3 ],
+[ 0.037829 , 24 , 0 , 4 ],
+[ 0.037973 , 25 , 1 , 3 ],
+[ 0.037999 , 25 , 1 , 4 ],
+[ 0.038011 , 25 , 1 , 5 ],
+[ 0.038174 , 26 , 3 , 3 ],
+[ 0.038183 , 26 , 3 , 4 ],
+[ 0.038663 , 28 , 3 , 3 ],
+[ 0.038672 , 28 , 3 , 4 ],
+[ 0.039153 , 30 , 3 , 3 ],
+[ 0.039162 , 30 , 3 , 4 ],
+[ 0.039779 , 32 , 0 , 3 ],
+[ 0.039788 , 32 , 0 , 4 ],
+[ 0.039932 , 33 , 1 , 3 ],
+[ 0.039958 , 33 , 1 , 4 ],
+[ 0.039970 , 33 , 1 , 5 ],
+[ 0.040133 , 34 , 3 , 3 ],
+[ 0.040142 , 34 , 3 , 4 ],
+[ 0.040656 , 36 , 2 , 3 ],
+[ 0.040663 , 36 , 2 , 4 ],
+[ 0.041111 , 38 , 4 , 3 ],
+[ 0.041133 , 38 , 4 , 4 ],
+[ 0.041145 , 38 , 4 , 5 ],
+[ 0.041602 , 40 , 3 , 3 ],
+[ 0.041611 , 40 , 3 , 4 ],
+[ 0.043401 , 2 , 1 , 6 ],
+[ 0.043434 , 1 , 0 , 5 ],
+[ 0.043447 , 1 , 0 , 6 ],
+[ 0.043815 , 3 , 2 , 5 ],
+[ 0.043873 , 4 , 3 , 5 ],
+[ 0.043886 , 4 , 3 , 6 ],
+[ 0.044082 , 6 , 5 , 4 ],
+[ 0.044570 , 7 , 6 , 4 ],
+[ 0.044831 , 8 , 7 , 4 ],
+[ 0.045090 , 5 , 4 , 6 ],
+[ 0.045449 , 10 , 9 , 5 ],
+[ 0.045694 , 11 , 10 , 5 ],
+[ 0.045839 , 12 , 11 , 4 ],
+[ 0.045998 , 9 , 8 , 4 ],
+[ 0.046032 , 13 , 12 , 4 ],
+[ 0.046300 , 14 , 13 , 4 ],
+[ 0.046705 , 16 , 15 , 4 ],
+[ 0.047031 , 17 , 16 , 4 ],
+[ 0.047809 , 20 , 1 , 6 ],
+[ 0.047842 , 19 , 0 , 5 ],
+[ 0.047854 , 19 , 0 , 6 ],
+[ 0.048035 , 21 , 3 , 5 ],
+[ 0.048048 , 21 , 3 , 6 ],
+[ 0.049033 , 25 , 1 , 6 ],
+[ 0.049066 , 24 , 0 , 5 ],
+[ 0.049079 , 24 , 0 , 6 ],
+[ 0.049253 , 22 , 4 , 6 ],
+[ 0.049260 , 26 , 3 , 5 ],
+[ 0.049273 , 26 , 3 , 6 ],
+[ 0.049749 , 28 , 3 , 5 ],
+[ 0.049763 , 28 , 3 , 6 ],
+[ 0.050239 , 30 , 3 , 5 ],
+[ 0.050252 , 30 , 3 , 6 ],
+[ 0.050992 , 33 , 1 , 6 ],
+[ 0.051025 , 32 , 0 , 5 ],
+[ 0.051038 , 32 , 0 , 6 ],
+[ 0.051219 , 34 , 3 , 5 ],
+[ 0.051232 , 34 , 3 , 6 ],
+[ 0.051895 , 36 , 2 , 5 ],
+[ 0.052688 , 40 , 3 , 5 ],
+[ 0.052701 , 40 , 3 , 6 ],
+[ 0.053171 , 38 , 4 , 6 ],
+[ 0.054470 , 2 , 1 , 7 ],
+[ 0.054487 , 2 , 1 , 8 ],
+[ 0.054500 , 2 , 1 , 9 ],
+[ 0.054521 , 1 , 0 , 7 ],
+[ 0.054932 , 4 , 3 , 7 ],
+[ 0.055104 , 6 , 5 , 5 ],
+[ 0.055245 , 3 , 2 , 6 ],
+[ 0.055432 , 8 , 7 , 5 ],
+[ 0.055610 , 7 , 6 , 5 ],
+[ 0.056678 , 10 , 9 , 6 ],
+[ 0.056889 , 12 , 11 , 5 ],
+[ 0.056923 , 11 , 10 , 6 ],
+[ 0.057032 , 9 , 8 , 5 ],
+[ 0.057064 , 13 , 12 , 5 ],
+[ 0.057126 , 5 , 4 , 7 ],
+[ 0.057323 , 14 , 13 , 5 ],
+[ 0.058054 , 17 , 16 , 5 ],
+[ 0.058877 , 20 , 1 , 7 ],
+[ 0.058895 , 20 , 1 , 8 ],
+[ 0.058907 , 20 , 1 , 9 ],
+[ 0.058928 , 19 , 0 , 7 ],
+[ 0.059094 , 21 , 3 , 7 ],
+[ 0.060102 , 25 , 1 , 7 ],
+[ 0.060119 , 25 , 1 , 8 ],
+[ 0.060132 , 25 , 1 , 9 ],
+[ 0.060153 , 24 , 0 , 7 ],
+[ 0.060319 , 26 , 3 , 7 ],
+[ 0.060372 , 16 , 15 , 5 ],
+[ 0.060808 , 28 , 3 , 7 ],
+[ 0.061288 , 22 , 4 , 7 ],
+[ 0.061298 , 30 , 3 , 7 ],
+[ 0.062061 , 33 , 1 , 7 ],
+[ 0.062078 , 33 , 1 , 8 ],
+[ 0.062091 , 33 , 1 , 9 ],
+[ 0.062112 , 32 , 0 , 7 ],
+[ 0.062278 , 34 , 3 , 7 ],
+[ 0.063325 , 36 , 2 , 6 ],
+[ 0.063747 , 40 , 3 , 7 ],
+[ 0.065206 , 38 , 4 , 7 ],
+[ 0.065542 , 2 , 1 , 10 ],
+[ 0.065601 , 1 , 0 , 8 ],
+[ 0.065614 , 1 , 0 , 9 ],
+[ 0.065626 , 1 , 0 , 10 ],
+[ 0.066011 , 4 , 3 , 8 ],
+[ 0.066023 , 4 , 3 , 9 ],
+[ 0.066036 , 4 , 3 , 10 ],
+[ 0.066140 , 6 , 5 , 6 ],
+[ 0.066484 , 8 , 7 , 6 ],
+[ 0.066651 , 7 , 6 , 6 ],
+[ 0.066656 , 3 , 2 , 7 ],
+[ 0.067815 , 10 , 9 , 7 ],
+[ 0.067928 , 12 , 11 , 6 ],
+[ 0.068060 , 11 , 10 , 7 ],
+[ 0.068094 , 13 , 12 , 6 ],
+[ 0.068149 , 14 , 13 , 6 ],
+[ 0.068160 , 5 , 4 , 8 ],
+[ 0.068463 , 15 , 14 , 4 ],
+[ 0.069950 , 20 , 1 , 10 ],
+[ 0.070008 , 19 , 0 , 8 ],
+[ 0.070022 , 19 , 0 , 9 ],
+[ 0.070034 , 19 , 0 , 10 ],
+[ 0.070173 , 21 , 3 , 8 ],
+[ 0.070185 , 21 , 3 , 9 ],
+[ 0.070199 , 21 , 3 , 10 ],
+[ 0.071174 , 25 , 1 , 10 ],
+[ 0.071233 , 24 , 0 , 8 ],
+[ 0.071246 , 24 , 0 , 9 ],
+[ 0.071258 , 24 , 0 , 10 ],
+[ 0.071398 , 26 , 3 , 8 ],
+[ 0.071410 , 26 , 3 , 9 ],
+[ 0.071423 , 26 , 3 , 10 ],
+[ 0.071888 , 28 , 3 , 8 ],
+[ 0.071899 , 28 , 3 , 9 ],
+[ 0.071913 , 28 , 3 , 10 ],
+[ 0.072091 , 17 , 16 , 6 ],
+[ 0.072322 , 22 , 4 , 8 ],
+[ 0.072377 , 30 , 3 , 8 ],
+[ 0.072389 , 30 , 3 , 9 ],
+[ 0.072402 , 30 , 3 , 10 ],
+[ 0.073133 , 33 , 1 , 10 ],
+[ 0.073192 , 32 , 0 , 8 ],
+[ 0.073205 , 32 , 0 , 9 ],
+[ 0.073217 , 32 , 0 , 10 ],
+[ 0.073357 , 34 , 3 , 8 ],
+[ 0.073369 , 34 , 3 , 9 ],
+[ 0.073382 , 34 , 3 , 10 ],
+[ 0.074736 , 36 , 2 , 7 ],
+[ 0.074826 , 40 , 3 , 8 ],
+[ 0.074838 , 40 , 3 , 9 ],
+[ 0.074851 , 40 , 3 , 10 ],
+[ 0.076240 , 38 , 4 , 8 ],
+[ 0.076607 , 2 , 1 , 11 ],
+[ 0.076621 , 2 , 1 , 12 ],
+[ 0.076633 , 2 , 1 , 13 ],
+[ 0.076661 , 1 , 0 , 11 ],
+[ 0.077065 , 4 , 3 , 11 ],
+[ 0.077162 , 6 , 5 , 7 ],
+[ 0.077509 , 8 , 7 , 7 ],
+[ 0.077678 , 7 , 6 , 7 ],
+[ 0.077745 , 3 , 2 , 8 ],
+[ 0.078888 , 10 , 9 , 8 ],
+[ 0.078959 , 12 , 11 , 7 ],
+[ 0.079126 , 13 , 12 , 7 ],
+[ 0.079133 , 11 , 10 , 8 ],
+[ 0.079189 , 14 , 13 , 7 ],
+[ 0.079212 , 5 , 4 , 9 ],
+[ 0.081015 , 20 , 1 , 11 ],
+[ 0.081028 , 20 , 1 , 12 ],
+[ 0.081041 , 20 , 1 , 13 ],
+[ 0.081068 , 19 , 0 , 11 ],
+[ 0.081227 , 21 , 3 , 11 ],
+[ 0.082239 , 25 , 1 , 11 ],
+[ 0.082253 , 25 , 1 , 12 ],
+[ 0.082265 , 25 , 1 , 13 ],
+[ 0.082293 , 24 , 0 , 11 ],
+[ 0.082452 , 26 , 3 , 11 ],
+[ 0.082941 , 28 , 3 , 11 ],
+[ 0.083374 , 22 , 4 , 9 ],
+[ 0.083431 , 30 , 3 , 11 ],
+[ 0.084198 , 33 , 1 , 11 ],
+[ 0.084212 , 33 , 1 , 12 ],
+[ 0.084224 , 33 , 1 , 13 ],
+[ 0.084252 , 32 , 0 , 11 ],
+[ 0.084411 , 34 , 3 , 11 ],
+[ 0.084412 , 15 , 14 , 5 ],
+[ 0.085546 , 15 , 14 , 6 ],
+[ 0.085825 , 36 , 2 , 8 ],
+[ 0.085880 , 40 , 3 , 11 ],
+[ 0.086057 , 9 , 8 , 6 ],
+[ 0.086065 , 9 , 8 , 7 ],
+[ 0.086070 , 9 , 8 , 8 ],
+[ 0.086120 , 17 , 16 , 7 ],
+[ 0.086549 , 15 , 14 , 7 ],
+[ 0.086558 , 15 , 14 , 8 ],
+[ 0.087122 , 17 , 16 , 8 ],
+[ 0.087127 , 17 , 16 , 9 ],
+[ 0.087133 , 17 , 16 , 10 ],
+[ 0.087138 , 17 , 16 , 11 ],
+[ 0.087148 , 17 , 16 , 12 ],
+[ 0.087292 , 38 , 4 , 9 ],
+[ 0.087381 , 2 , 1 , 14 ],
+[ 0.087410 , 2 , 1 , 15 ],
+[ 0.087423 , 2 , 1 , 16 ],
+[ 0.087727 , 1 , 0 , 12 ],
+[ 0.087740 , 1 , 0 , 13 ],
+[ 0.087753 , 1 , 0 , 14 ],
+[ 0.088122 , 17 , 16 , 13 ],
+[ 0.088152 , 4 , 3 , 12 ],
+[ 0.088164 , 4 , 3 , 13 ],
+[ 0.088176 , 4 , 3 , 14 ],
+[ 0.088200 , 6 , 5 , 8 ],
+[ 0.088521 , 8 , 7 , 8 ],
+[ 0.088709 , 7 , 6 , 8 ],
+[ 0.088855 , 3 , 2 , 9 ],
+[ 0.088868 , 3 , 2 , 10 ],
+[ 0.088880 , 3 , 2 , 11 ],
+[ 0.088893 , 3 , 2 , 12 ],
+[ 0.089129 , 17 , 16 , 14 ],
+[ 0.089137 , 17 , 16 , 15 ],
+[ 0.089142 , 17 , 16 , 16 ],
+[ 0.089147 , 17 , 16 , 17 ],
+[ 0.089152 , 17 , 16 , 18 ],
+[ 0.089550 , 15 , 14 , 9 ],
+[ 0.089559 , 15 , 14 , 10 ],
+[ 0.089954 , 10 , 9 , 9 ],
+[ 0.089997 , 12 , 11 , 8 ],
+[ 0.090130 , 17 , 16 , 19 ],
+[ 0.090135 , 17 , 16 , 20 ],
+[ 0.090141 , 17 , 16 , 21 ],
+[ 0.090169 , 13 , 12 , 8 ],
+[ 0.090199 , 11 , 10 , 9 ],
+[ 0.090232 , 14 , 13 , 8 ],
+[ 0.091788 , 20 , 1 , 14 ],
+[ 0.091818 , 20 , 1 , 15 ],
+[ 0.091830 , 20 , 1 , 16 ],
+[ 0.092134 , 19 , 0 , 12 ],
+[ 0.092147 , 17 , 16 , 22 ],
+[ 0.092148 , 19 , 0 , 13 ],
+[ 0.092152 , 17 , 16 , 23 ],
+[ 0.092160 , 19 , 0 , 14 ],
+[ 0.092186 , 17 , 16 , 24 ],
+[ 0.092192 , 17 , 16 , 25 ],
+[ 0.092198 , 17 , 16 , 26 ],
+[ 0.092272 , 5 , 4 , 10 ],
+[ 0.092314 , 21 , 3 , 12 ],
+[ 0.092326 , 21 , 3 , 13 ],
+[ 0.092338 , 21 , 3 , 14 ],
+[ 0.093013 , 25 , 1 , 14 ],
+[ 0.093042 , 25 , 1 , 15 ],
+[ 0.093055 , 25 , 1 , 16 ],
+[ 0.093154 , 17 , 16 , 27 ],
+[ 0.093160 , 17 , 16 , 28 ],
+[ 0.093359 , 24 , 0 , 12 ],
+[ 0.093372 , 24 , 0 , 13 ],
+[ 0.093385 , 24 , 0 , 14 ],
+[ 0.093539 , 26 , 3 , 12 ],
+[ 0.093551 , 26 , 3 , 13 ],
+[ 0.093563 , 26 , 3 , 14 ],
+[ 0.094029 , 28 , 3 , 12 ],
+[ 0.094040 , 28 , 3 , 13 ],
+[ 0.094052 , 28 , 3 , 14 ],
+[ 0.094518 , 30 , 3 , 12 ],
+[ 0.094530 , 30 , 3 , 13 ],
+[ 0.094542 , 30 , 3 , 14 ],
+[ 0.094972 , 33 , 1 , 14 ],
+[ 0.095001 , 33 , 1 , 15 ],
+[ 0.095014 , 33 , 1 , 16 ],
+[ 0.095318 , 32 , 0 , 12 ],
+[ 0.095331 , 32 , 0 , 13 ],
+[ 0.095344 , 32 , 0 , 14 ],
+[ 0.095498 , 34 , 3 , 12 ],
+[ 0.095510 , 34 , 3 , 13 ],
+[ 0.095522 , 34 , 3 , 14 ],
+[ 0.096434 , 22 , 4 , 10 ],
+[ 0.096935 , 36 , 2 , 9 ],
+[ 0.096948 , 36 , 2 , 10 ],
+[ 0.096960 , 36 , 2 , 11 ],
+[ 0.096967 , 40 , 3 , 12 ],
+[ 0.096973 , 36 , 2 , 12 ],
+[ 0.096979 , 40 , 3 , 13 ],
+[ 0.096991 , 40 , 3 , 14 ],
+[ 0.098100 , 9 , 8 , 9 ],
+[ 0.098440 , 2 , 1 , 17 ],
+[ 0.098777 , 1 , 0 , 15 ],
+[ 0.098783 , 1 , 0 , 16 ],
+[ 0.099207 , 4 , 3 , 15 ],
+[ 0.099216 , 4 , 3 , 16 ],
+[ 0.099234 , 6 , 5 , 9 ],
+[ 0.099540 , 8 , 7 , 9 ],
+[ 0.099733 , 7 , 6 , 9 ],
+[ 0.099913 , 3 , 2 , 13 ],
+[ 0.099918 , 3 , 2 , 14 ],
+[ 0.100352 , 38 , 4 , 10 ],
+[ 0.101031 , 10 , 9 , 10 ],
+[ 0.101033 , 12 , 11 , 9 ],
+[ 0.101218 , 13 , 12 , 9 ],
+[ 0.101264 , 14 , 13 , 9 ],
+[ 0.101276 , 11 , 10 , 10 ],
+[ 0.102848 , 20 , 1 , 17 ],
+[ 0.103184 , 19 , 0 , 15 ],
+[ 0.103190 , 19 , 0 , 16 ],
+[ 0.103369 , 21 , 3 , 15 ],
+[ 0.103379 , 21 , 3 , 16 ],
+[ 0.104072 , 25 , 1 , 17 ],
+[ 0.104409 , 24 , 0 , 15 ],
+[ 0.104415 , 24 , 0 , 16 ],
+[ 0.104594 , 26 , 3 , 15 ],
+[ 0.104603 , 26 , 3 , 16 ],
+[ 0.105084 , 28 , 3 , 15 ],
+[ 0.105093 , 28 , 3 , 16 ],
+[ 0.105573 , 30 , 3 , 15 ],
+[ 0.105582 , 30 , 3 , 16 ],
+[ 0.106031 , 33 , 1 , 17 ],
+[ 0.106368 , 32 , 0 , 15 ],
+[ 0.106374 , 32 , 0 , 16 ],
+[ 0.106553 , 34 , 3 , 15 ],
+[ 0.106562 , 34 , 3 , 16 ],
+[ 0.107993 , 36 , 2 , 13 ],
+[ 0.107998 , 36 , 2 , 14 ],
+[ 0.108022 , 40 , 3 , 15 ],
+[ 0.108031 , 40 , 3 , 16 ],
+[ 0.109544 , 2 , 1 , 18 ],
+[ 0.109578 , 2 , 1 , 19 ],
+[ 0.109590 , 2 , 1 , 20 ],
+[ 0.109842 , 1 , 0 , 17 ],
+[ 0.109854 , 1 , 0 , 18 ],
+[ 0.109867 , 1 , 0 , 19 ],
+[ 0.109879 , 1 , 0 , 20 ],
+[ 0.109891 , 1 , 0 , 21 ],
+[ 0.109904 , 1 , 0 , 22 ],
+[ 0.110264 , 6 , 5 , 10 ],
+[ 0.110291 , 4 , 3 , 17 ],
+[ 0.110304 , 4 , 3 , 18 ],
+[ 0.110316 , 4 , 3 , 19 ],
+[ 0.110329 , 4 , 3 , 20 ],
+[ 0.110341 , 4 , 3 , 21 ],
+[ 0.110353 , 4 , 3 , 22 ],
+[ 0.110567 , 8 , 7 , 10 ],
+[ 0.110762 , 7 , 6 , 10 ],
+[ 0.110992 , 3 , 2 , 15 ],
+[ 0.111005 , 3 , 2 , 16 ],
+[ 0.111017 , 3 , 2 , 17 ],
+[ 0.111029 , 3 , 2 , 18 ],
+[ 0.111042 , 3 , 2 , 19 ],
+[ 0.111054 , 3 , 2 , 20 ],
+[ 0.112076 , 12 , 11 , 10 ],
+[ 0.112154 , 10 , 9 , 11 ],
+[ 0.112274 , 13 , 12 , 10 ],
+[ 0.112291 , 14 , 13 , 10 ],
+[ 0.112399 , 11 , 10 , 11 ],
+[ 0.113951 , 20 , 1 , 18 ],
+[ 0.113986 , 20 , 1 , 19 ],
+[ 0.113997 , 20 , 1 , 20 ],
+[ 0.114249 , 19 , 0 , 17 ],
+[ 0.114262 , 19 , 0 , 18 ],
+[ 0.114274 , 19 , 0 , 19 ],
+[ 0.114286 , 19 , 0 , 20 ],
+[ 0.114299 , 19 , 0 , 21 ],
+[ 0.114311 , 19 , 0 , 22 ],
+[ 0.114453 , 21 , 3 , 17 ],
+[ 0.114466 , 21 , 3 , 18 ],
+[ 0.114478 , 21 , 3 , 19 ],
+[ 0.114491 , 21 , 3 , 20 ],
+[ 0.114503 , 21 , 3 , 21 ],
+[ 0.114515 , 21 , 3 , 22 ],
+[ 0.115148 , 9 , 8 , 10 ],
+[ 0.115176 , 25 , 1 , 18 ],
+[ 0.115210 , 25 , 1 , 19 ],
+[ 0.115222 , 25 , 1 , 20 ],
+[ 0.115474 , 24 , 0 , 17 ],
+[ 0.115486 , 24 , 0 , 18 ],
+[ 0.115499 , 24 , 0 , 19 ],
+[ 0.115511 , 24 , 0 , 20 ],
+[ 0.115523 , 24 , 0 , 21 ],
+[ 0.115536 , 24 , 0 , 22 ],
+[ 0.115678 , 26 , 3 , 17 ],
+[ 0.115691 , 26 , 3 , 18 ],
+[ 0.115703 , 26 , 3 , 19 ],
+[ 0.115716 , 26 , 3 , 20 ],
+[ 0.115728 , 26 , 3 , 21 ],
+[ 0.115740 , 26 , 3 , 22 ],
+[ 0.116167 , 28 , 3 , 17 ],
+[ 0.116180 , 28 , 3 , 18 ],
+[ 0.116192 , 28 , 3 , 19 ],
+[ 0.116206 , 28 , 3 , 20 ],
+[ 0.116217 , 28 , 3 , 21 ],
+[ 0.116229 , 28 , 3 , 22 ],
+[ 0.116657 , 30 , 3 , 17 ],
+[ 0.116670 , 30 , 3 , 18 ],
+[ 0.116682 , 30 , 3 , 19 ],
+[ 0.116695 , 30 , 3 , 20 ],
+[ 0.116707 , 30 , 3 , 21 ],
+[ 0.116719 , 30 , 3 , 22 ],
+[ 0.117135 , 33 , 1 , 18 ],
+[ 0.117169 , 33 , 1 , 19 ],
+[ 0.117181 , 33 , 1 , 20 ],
+[ 0.117433 , 32 , 0 , 17 ],
+[ 0.117445 , 32 , 0 , 18 ],
+[ 0.117458 , 32 , 0 , 19 ],
+[ 0.117470 , 32 , 0 , 20 ],
+[ 0.117482 , 32 , 0 , 21 ],
+[ 0.117495 , 32 , 0 , 22 ],
+[ 0.117637 , 34 , 3 , 17 ],
+[ 0.117650 , 34 , 3 , 18 ],
+[ 0.117662 , 34 , 3 , 19 ],
+[ 0.117675 , 34 , 3 , 20 ],
+[ 0.117687 , 34 , 3 , 21 ],
+[ 0.117699 , 34 , 3 , 22 ],
+[ 0.119072 , 36 , 2 , 15 ],
+[ 0.119085 , 36 , 2 , 16 ],
+[ 0.119097 , 36 , 2 , 17 ],
+[ 0.119106 , 40 , 3 , 17 ],
+[ 0.119109 , 36 , 2 , 18 ],
+[ 0.119119 , 40 , 3 , 18 ],
+[ 0.119122 , 36 , 2 , 19 ],
+[ 0.119131 , 40 , 3 , 19 ],
+[ 0.119134 , 36 , 2 , 20 ],
+[ 0.119144 , 40 , 3 , 20 ],
+[ 0.119156 , 40 , 3 , 21 ],
+[ 0.119168 , 40 , 3 , 22 ],
+[ 0.120605 , 2 , 1 , 21 ],
+[ 0.120900 , 1 , 0 , 23 ],
+[ 0.120910 , 1 , 0 , 24 ],
+[ 0.120914 , 1 , 0 , 25 ],
+[ 0.121289 , 6 , 5 , 11 ],
+[ 0.121346 , 4 , 3 , 23 ],
+[ 0.121352 , 4 , 3 , 24 ],
+[ 0.121357 , 4 , 3 , 25 ],
+[ 0.121601 , 8 , 7 , 11 ],
+[ 0.121787 , 7 , 6 , 11 ],
+[ 0.122057 , 3 , 2 , 21 ],
+[ 0.122062 , 3 , 2 , 22 ],
+[ 0.122066 , 3 , 2 , 23 ],
+[ 0.123109 , 12 , 11 , 11 ],
+[ 0.123312 , 14 , 13 , 11 ],
+[ 0.123322 , 13 , 12 , 11 ],
+[ 0.125013 , 20 , 1 , 21 ],
+[ 0.125308 , 19 , 0 , 23 ],
+[ 0.125318 , 19 , 0 , 24 ],
+[ 0.125322 , 19 , 0 , 25 ],
+[ 0.125508 , 21 , 3 , 23 ],
+[ 0.125514 , 21 , 3 , 24 ],
+[ 0.125519 , 21 , 3 , 25 ],
+[ 0.125629 , 15 , 14 , 11 ],
+[ 0.126237 , 25 , 1 , 21 ],
+[ 0.126532 , 24 , 0 , 23 ],
+[ 0.126542 , 24 , 0 , 24 ],
+[ 0.126546 , 24 , 0 , 25 ],
+[ 0.126724 , 9 , 8 , 11 ],
+[ 0.126733 , 26 , 3 , 23 ],
+[ 0.126739 , 26 , 3 , 24 ],
+[ 0.126744 , 26 , 3 , 25 ],
+[ 0.127222 , 28 , 3 , 23 ],
+[ 0.127229 , 28 , 3 , 24 ],
+[ 0.127234 , 28 , 3 , 25 ],
+[ 0.127712 , 30 , 3 , 23 ],
+[ 0.127718 , 30 , 3 , 24 ],
+[ 0.127723 , 30 , 3 , 25 ],
+[ 0.128196 , 33 , 1 , 21 ],
+[ 0.128491 , 32 , 0 , 23 ],
+[ 0.128501 , 32 , 0 , 24 ],
+[ 0.128505 , 32 , 0 , 25 ],
+[ 0.128692 , 34 , 3 , 23 ],
+[ 0.128698 , 34 , 3 , 24 ],
+[ 0.128703 , 34 , 3 , 25 ],
+[ 0.130137 , 36 , 2 , 21 ],
+[ 0.130142 , 36 , 2 , 22 ],
+[ 0.130146 , 36 , 2 , 23 ],
+[ 0.130161 , 40 , 3 , 23 ],
+[ 0.130167 , 40 , 3 , 24 ],
+[ 0.130172 , 40 , 3 , 25 ],
+[ 0.131565 , 1 , 0 , 26 ],
+[ 0.131578 , 1 , 0 , 27 ],
+[ 0.131590 , 1 , 0 , 28 ],
+[ 0.131603 , 1 , 0 , 29 ],
+[ 0.131615 , 1 , 0 , 30 ],
+[ 0.131627 , 1 , 0 , 31 ],
+[ 0.131640 , 1 , 0 , 32 ],
+[ 0.131652 , 1 , 0 , 33 ],
+[ 0.131664 , 1 , 0 , 34 ],
+[ 0.131689 , 2 , 1 , 22 ],
+[ 0.131702 , 2 , 1 , 23 ],
+[ 0.131715 , 2 , 1 , 24 ],
+[ 0.132022 , 4 , 3 , 26 ],
+[ 0.132035 , 4 , 3 , 27 ],
+[ 0.132047 , 4 , 3 , 28 ],
+[ 0.132060 , 4 , 3 , 29 ],
+[ 0.132072 , 4 , 3 , 30 ],
+[ 0.132084 , 4 , 3 , 31 ],
+[ 0.132097 , 4 , 3 , 32 ],
+[ 0.132109 , 4 , 3 , 33 ],
+[ 0.132387 , 6 , 5 , 12 ],
+[ 0.132399 , 6 , 5 , 13 ],
+[ 0.132412 , 6 , 5 , 14 ],
+[ 0.132701 , 8 , 7 , 12 ],
+[ 0.132714 , 8 , 7 , 13 ],
+[ 0.132723 , 3 , 2 , 24 ],
+[ 0.132727 , 8 , 7 , 14 ],
+[ 0.132735 , 3 , 2 , 25 ],
+[ 0.132739 , 8 , 7 , 15 ],
+[ 0.132747 , 3 , 2 , 26 ],
+[ 0.132751 , 8 , 7 , 16 ],
+[ 0.132760 , 3 , 2 , 27 ],
+[ 0.132764 , 8 , 7 , 17 ],
+[ 0.132772 , 3 , 2 , 28 ],
+[ 0.132784 , 3 , 2 , 29 ],
+[ 0.132796 , 3 , 2 , 30 ],
+[ 0.132809 , 3 , 2 , 31 ],
+[ 0.132821 , 3 , 2 , 32 ],
+[ 0.132907 , 7 , 6 , 12 ],
+[ 0.132920 , 7 , 6 , 13 ],
+[ 0.132932 , 7 , 6 , 14 ],
+[ 0.132944 , 7 , 6 , 15 ],
+[ 0.132957 , 7 , 6 , 16 ],
+[ 0.132969 , 7 , 6 , 17 ],
+[ 0.134138 , 12 , 11 , 12 ],
+[ 0.134162 , 14 , 13 , 12 ],
+[ 0.134377 , 13 , 12 , 12 ],
+[ 0.135972 , 19 , 0 , 26 ],
+[ 0.135986 , 19 , 0 , 27 ],
+[ 0.135997 , 19 , 0 , 28 ],
+[ 0.136011 , 19 , 0 , 29 ],
+[ 0.136023 , 19 , 0 , 30 ],
+[ 0.136034 , 19 , 0 , 31 ],
+[ 0.136048 , 19 , 0 , 32 ],
+[ 0.136059 , 19 , 0 , 33 ],
+[ 0.136071 , 19 , 0 , 34 ],
+[ 0.136096 , 20 , 1 , 22 ],
+[ 0.136110 , 20 , 1 , 23 ],
+[ 0.136122 , 20 , 1 , 24 ],
+[ 0.136184 , 21 , 3 , 26 ],
+[ 0.136197 , 21 , 3 , 27 ],
+[ 0.136209 , 21 , 3 , 28 ],
+[ 0.136222 , 21 , 3 , 29 ],
+[ 0.136235 , 21 , 3 , 30 ],
+[ 0.136246 , 21 , 3 , 31 ],
+[ 0.136259 , 21 , 3 , 32 ],
+[ 0.136271 , 21 , 3 , 33 ],
+[ 0.137197 , 24 , 0 , 26 ],
+[ 0.137210 , 24 , 0 , 27 ],
+[ 0.137222 , 24 , 0 , 28 ],
+[ 0.137235 , 24 , 0 , 29 ],
+[ 0.137247 , 24 , 0 , 30 ],
+[ 0.137259 , 24 , 0 , 31 ],
+[ 0.137272 , 24 , 0 , 32 ],
+[ 0.137284 , 24 , 0 , 33 ],
+[ 0.137296 , 24 , 0 , 34 ],
+[ 0.137321 , 25 , 1 , 22 ],
+[ 0.137334 , 25 , 1 , 23 ],
+[ 0.137347 , 25 , 1 , 24 ],
+[ 0.137409 , 26 , 3 , 26 ],
+[ 0.137422 , 26 , 3 , 27 ],
+[ 0.137434 , 26 , 3 , 28 ],
+[ 0.137447 , 26 , 3 , 29 ],
+[ 0.137459 , 26 , 3 , 30 ],
+[ 0.137471 , 26 , 3 , 31 ],
+[ 0.137484 , 26 , 3 , 32 ],
+[ 0.137496 , 26 , 3 , 33 ],
+[ 0.137898 , 28 , 3 , 26 ],
+[ 0.137911 , 28 , 3 , 27 ],
+[ 0.137924 , 28 , 3 , 28 ],
+[ 0.137936 , 28 , 3 , 29 ],
+[ 0.137949 , 28 , 3 , 30 ],
+[ 0.137960 , 28 , 3 , 31 ],
+[ 0.137973 , 28 , 3 , 32 ],
+[ 0.137986 , 28 , 3 , 33 ],
+[ 0.138388 , 30 , 3 , 26 ],
+[ 0.138401 , 30 , 3 , 27 ],
+[ 0.138413 , 30 , 3 , 28 ],
+[ 0.138426 , 30 , 3 , 29 ],
+[ 0.138438 , 30 , 3 , 30 ],
+[ 0.138450 , 30 , 3 , 31 ],
+[ 0.138463 , 30 , 3 , 32 ],
+[ 0.138475 , 30 , 3 , 33 ],
+[ 0.138784 , 9 , 8 , 12 ],
+[ 0.139156 , 32 , 0 , 26 ],
+[ 0.139169 , 32 , 0 , 27 ],
+[ 0.139181 , 32 , 0 , 28 ],
+[ 0.139194 , 32 , 0 , 29 ],
+[ 0.139206 , 32 , 0 , 30 ],
+[ 0.139218 , 32 , 0 , 31 ],
+[ 0.139231 , 32 , 0 , 32 ],
+[ 0.139243 , 32 , 0 , 33 ],
+[ 0.139255 , 32 , 0 , 34 ],
+[ 0.139280 , 33 , 1 , 22 ],
+[ 0.139293 , 33 , 1 , 23 ],
+[ 0.139306 , 33 , 1 , 24 ],
+[ 0.139368 , 34 , 3 , 26 ],
+];
+
+sfr_names=["http_get",
+ "http_post",
+ "https",
+ "http_browsing",
+ "exchange",
+ "mail_pop",
+ "mail_pop_1",
+ "mail_pop_2",
+ "oracle_0",
+ "rtp_160k",
+ "rtp_250k",
+ "smtp_0",
+ "smtp_1",
+ "smtp_2",
+ "video_call",
+ "sip_video_call_full",
+ "citrix_0",
+ "dns_0"];
+
+chart("#chart4",sfr_data,sfr_names,"time-sec","flow-id");
+</script>
++++++++++++++++++++++++++++++++++
+
+== TRex command line main options
+
+[source,bash]
+----
+$.sudo /t-rex-64 -f [traffic_yaml] -m [muti] -d [duration] -l [Hz=1000] -c [cores]
+----
+
+*-f=TRAFFIC_CFG* ::
+ Traffic YAML configuration file
+
+*-m*::
+ CPS multiplier
+
+*-d=DURATION* ::
+ Duration of the test in sec
+
+*-l=Hz* ::
+ Latency pakets rate (Hz)
+
+*-c*::
+ How many cores to use
+
+
+== TRex Vision
+
+* All in One, most of the functionality of existing tools
+* Standard tests (e.g. traffic mix, automation) across features/platforms
+* Cisco wide developers community
+* Open source, Standardize tests
+
+== TRex GUI
+
+image:images/TrexViewer.png[width=500]
+
+* Monitor GUI works on Windows 7
+* Nonitor real-time properties of TRex ( e.g min/max/average latency,jitter )
+
+== Python API and automation tools
+
+++++++++++++++++++
+<img src="images/trex_control_plane_modules.png" alt="title=" align="center" >
+
+<div id="pclient" >
+
+++++++++++++++++++
+
+[source,python]
+-----
+import trex_client
+
+ trex = trex_client.CTRexClient('csi-kiwi-02')
+ ret = trex.start_trex(
+ m = 1.1,
+ d = 20,
+ f = 'avl/sfr_delay_10_1g.yaml',
+ l = 1000)
+
+ while trex.is_running() :
+ trex.get_running_info()
+ res=trex.get_result_obj()
+ if res.is_done_warmup ():
+ res.get_value_list("trex-global.data.m_tx_bps");
+ time.sleep(1);
+
+ ret = trex.stop_trex()
+-----
+
+++++++++++++++++++
+</div>
+
+<script>
+ $("#pclient").css({'font-size':'12px'})
+ </script>
+++++++++++++++++++
+
+
+== TRex On your laptop
+
+++++++++++++++++++
+<img src="images/T-Rex_vm.png" alt="title=" align="center" >
+++++++++++++++++++
+
+* You can experience TRex on your laptop
+
+== Roadmap
+
+* TCP stack
+* Export SDK application plugins API - more application support
+* Automation (e.g ATS, Cisco HLTAPI etc)
+* Open source
+* Tunnel agnostic (e.g. VXLAN,QinQ,MPLS,NSH)
+
+== Benefit
+
+** Significant budget saving
+** Product quality
+
+== Resource
+
+.Resource
+[options="header",cols="1^",width="40%"]
+|=================
+| Link
+| link:trex_manual.html[Manual-html]
+| link:trex_book.pdf[Manual-pdf]
+| link:release_notes.html[Release Notes]
+| link:trex_manual.html#_download_and_installation[How to install]
+|=================
+
+
+++++++++++++++++++
+</section>
+<section class="slide">
+<h2></h2>
+<h7>Backup</h7>
+<h8></h8>
+</section>
+++++++++++++++++++
+
+
+
+
diff --git a/doc/trex_rpc_server_spec-docinfo.html b/doc/trex_rpc_server_spec-docinfo.html
new file mode 100644
index 00000000..6fb66a5e
--- /dev/null
+++ b/doc/trex_rpc_server_spec-docinfo.html
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/doc/trex_rpc_server_spec.asciidoc b/doc/trex_rpc_server_spec.asciidoc
new file mode 100755
index 00000000..643a89b3
--- /dev/null
+++ b/doc/trex_rpc_server_spec.asciidoc
@@ -0,0 +1,2092 @@
+The TRex RPC Server
+===================
+:Author: Itay Marom, Dan Klein
+:email: trex-dev@cisco.com
+:revnumber: 1.1
+:quotes.++:
+:numbered:
+:web_server_url: https://trex-tgn.cisco.com/trex
+:local_web_server_url: csi-wiki-01:8181/trex
+:toclevels: 7
+
+include::trex_ga.asciidoc[]
+
+== Change log
+
+[options="header",cols="^1,^h,3a"]
+|=================
+| Version | name | meaning
+| 1.00 | Itay Marom (imarom) |
+- first version
+| 1.01 | Dan Klein (danklei)
+|
+- added usage examples using Python code as Higher-level usage
+- added logic and explanation behind VM commands
+| 1.1 | Dan Klein (danklei)
+|
+- Fixed some consistency issues
+- added RPC interaction examples appendix
+| 1.2 | Hanoch Haim (hhaim)
+|
+- add tuple generator command
+| 1.3 | Hanoch Haim (hhaim)
+|
+- update VM instructions
+| 1.4 | Hanoch Haim (hhaim)
+|
+- add random trim instruction
+| 1.5 | Hanoch Haim (hhaim)
+|
+- add more instructions (v1.92)
+| 1.6 | Itay Marom (imarom)
+|
+- added API synchronization
+|=================
+
+
+== Audience of this document
+
+Anyone that wants to understand the low level protocol to TRex server. for example a GUI developer that wants to develop a GUI for TRex Server.
+
+== RPC Support On TRex
+
+TRex implements a RPC protocol in order to config, view and
+in general execute remote calls on TRex
+
+In this document we will provide information on
+how a client can implement the protocol used to communicate with TRex
+
+In general, we will describe the following:
+
+* *Transport Layer* - The transport layer used to communicate with TRex server
+* *RPC Reprensentation Protocol* - The format in which remote procedures are carried
+
+=== Transport Layer
+
+TRex server transport layer is implemented using ZMQ.
+
+The default configuration is TCP on port 5555, however this is configurable.
+
+{zwsp} +
+The communication model is based on the request-reply ZMQ model:
+
+http://zguide.zeromq.org/page:all#Ask-and-Ye-Shall-Receive
+
+{zwsp} +
+
+for more on ZMQ and implementation please refer to:
+{zwsp} +
+http://zeromq.org/intro:read-the-manual
+
+=== RPC Reprensentation Protocol
+
+The RPC reprensentation protocol is JSON RPC v2.0.
+Every request and response will be encoded in a JSON RPC v2.0 format.
+
+{zwsp}+
+For more info on JSON RPC v2.0 spec please refer to:
+{zwsp}+
+
+http://www.jsonrpc.org/specification
+
+{zwsp}+
+
+Later on in the document we will describe all the supported commands.
+
+=== TRex Console
+
+To debug RPC it is possible to enable verbose command from Console see link:draft_trex_stateless.html#_console_commands[here]
+
+On the 'client' side:
+
+[source,bash]
+----
+TRex > verbose on
+
+verbose set to on
+
+TRex > ping
+
+-> Pinging RPC server
+[verbose] Sending Request To Server:
+
+{
+ "id": "l0tog11a",
+ "jsonrpc": "2.0",
+ "method": "ping",
+ "params": null
+}
+
+[verbose] Server Response:
+
+{
+ "id": "l0tog11a",
+ "jsonrpc": "2.0",
+ "result": {}
+}
+
+[SUCCESS]
+
+----
+
+== RPC Server Component Position Illustration
+
+The following diagram illustres the RPC server component's place:
+
+image::images/rpc_server_big_picture.png[title="RPC Server Position",align="left",width=800, link="images/rpc_server_big_picture.png"]
+
+== RPC Server Port State Machine
+Any port on the server can be in numbered of states, each state provides other subset of the commands
+that are allowed to be executed.
+
+We define the following possible states:
+
+* *unowned* - The specific port is either unowned or another user is owning the port
+* *owned* - The specific port has been acquired by the client
+* *active* - The specific port is in the middle of injecting traffic - currently active
+
+Each port command will specify on which states it is possible to execute it.
+
+For port related commands valid only on 'owned' or 'active', a field called ''handler'' 'MUST' be passed
+along with the rest of the parameters.
+
+
+This will identify the connection:
+
+image::images/rpc_states.png[title="Port States",align="left",width=150, link="images/rpc_states.png"]
+
+== RPC Commands
+The following RPC commands are supported
+
+=== API Synchronization
+* *Name* - 'api_sync'
+* *API Class* - 'None'
+* *Valid States* - 'not relevant'
+* *Description* - Sync with server about API classes. This allows the server and the client
+ to be sure they are fully synced.
+ The return values are used for furthur communication with the server.
+ every API from a specific class requires its corresponding api_h parameter
+ added to the specific parameters of the function.
+* *Parameters* -
+** *api_vers* [list] - A list of objects of type xref:api_class['api_class']
+* *Result* ['object'] - A list of objects of type xref:api_class_rc['api_class_rc']
+
+.Object type 'api_class'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | name of the API class
+| major | int | major version
+| minor | int | minor version
+|=================
+
+.Object type 'api_class_rc'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | name of the API class
+| api_h | string | API handler for this API class
+|=================
+
+Example:
+
+[source,bash]
+----
+'Request':
+
+{
+ "id": "6d4e9gs3",
+ "jsonrpc": "2.0",
+ "method": "api_sync",
+ "params": {
+ "api_vers": [
+ {
+ "type": "core"
+ "major": 1,
+ "minor": 0,
+ }
+ ]
+ }
+}
+
+'Response':
+
+{
+ "id": "6d4e9gs3",
+ "jsonrpc": "2.0",
+ "result": {
+ "api_vers": [
+ {
+ "type": "core"
+ "api_h": "SPhoCDIV",
+ }
+ ]
+ }
+}
+
+----
+
+=== Ping
+* *Name* - 'ping'
+* *API Class* - 'None'
+* *Valid States* - 'not relevant'
+* *Description* - Pings the TRex server
+* *Parameters* - None
+* *Result* ['object'] - {}
+
+Example:
+
+[source,bash]
+----
+'Request':
+
+{
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": "ping",
+ "params": null
+}
+
+'Response':
+
+{
+ "jsonrpc" : "2.0",
+ "id" : 1,
+ "result" : {}
+}
+
+----
+
+=== Get Server Supported Commands
+* *Name* - 'get_supported_cmds'
+* *API Class* - 'core'
+* *Valid States* - 'not relevant'
+* *Description* - Queries the server for all the supported commands
+* *Parameters* - None
+* *Result* ['array'] - A list of all the supported commands by the server
+
+Example:
+
+[source,bash]
+----
+'Request':
+
+{
+ "id": "7rqf0xyd",
+ "jsonrpc": "2.0",
+ "method": "get_supported_cmds",
+ "params": {
+ "api_h": "VGDJwdiY"
+ }
+}
+
+
+'Response':
+
+{
+ "id": "7rqf0xyd",
+ "jsonrpc": "2.0",
+ "result": [
+ "push_remote",
+ "validate",
+ "start_traffic",
+ "get_all_streams",
+ "shutdown",
+ "get_stream",
+ "test_add",
+ "stop_traffic",
+ "get_utilization",
+ "release",
+ "test_sub",
+ "api_sync",
+ "get_port_status",
+ "get_port_stats",
+ "publish_now",
+ "get_system_info",
+ "get_supported_cmds",
+ "get_version",
+ "get_port_xstats_names",
+ "update_traffic",
+ "get_active_pgids",
+ "pause_traffic",
+ "get_owner",
+ "acquire",
+ "set_port_attr",
+ "get_port_xstats_values",
+ "remove_rx_filters",
+ "resume_traffic",
+ "add_stream",
+ "remove_stream",
+ "remove_all_streams",
+ "ping",
+ "get_stream_list"
+ ]
+}
+
+
+----
+
+
+=== Get Version
+* *Name* - 'get_version'
+* *API Class* - 'core'
+* *Valid States* - 'not relevant'
+* *Description* - Queries the server for version information
+* *Parameters* - None
+* *Result* ['object'] - See table below
+
+.Object type 'return values for get_version'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| version | string | TRex version
+| build_date | string | build date
+| build_time | string | build time
+| built_by | string | who built this version
+|=================
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": "wapkk8m6",
+ "jsonrpc": "2.0",
+ "method": "get_version",
+ "params": {
+ "api_h": "SPhoCDIV"
+ }
+}
+
+
+'Response':
+
+{
+ "id": "wapkk8m6",
+ "jsonrpc": "2.0",
+ "result": {
+ "build_date": "Sep 16 2015",
+ "build_time": "12:33:01",
+ "built_by": "imarom",
+ "version": "v0.0"
+ }
+}
+
+----
+
+=== Get System Info
+* *Name* - 'get_system_info'
+* *API Class* - 'core'
+* *Description* - Queries the server for system properties
+* *Parameters* - None
+* *Result* ['object'] - See table below
+
+.return value: 'get_system_info'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| dp_core_count | int | DP core count (total)
+| dp_core_count_per_port | int | DP core count per pair of ports
+| core_type | string | DP core type
+| hostname | string | machine host name
+| uptime | string | uptime of the server
+| port_count | int | number of ports on the machine
+| ports | array | array of object ''ports'' - see below
+|=================
+
+.return value: 'get_system_info'.'ports'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| description | string | description of port
+| driver | string | driver type
+| numa | int | NUMA of port
+| pci_addr | string | PCI address of port
+| hw_macaddr | string | HW MAC of port (masked by src_macaddr)
+| src_macaddr | string | src MAC of port
+| dst_macaddr | string | dest MAC of port
+| is_virtual | bool | is port virtual
+| is_fc_supported | bool | is flow control supported
+| is_led_supported | bool | is led on/off supported
+| is_link_supported | bool | is link status change supported
+| index | int | port index
+| speed | int | current max speed of the port (1, 10, 40, 100)
+| supp_speeds | array | list of max speeds supported by port
+| rx | object | see below
+|=================
+
+.return value: 'get_system_info'.'ports'.'rx'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| caps | array | list of capabilities: "flow_stats", "latency" etc.
+| counters | int | number of different pg_ids one can use at the same time
+|=================
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": "kn92anod",
+ "jsonrpc": "2.0",
+ "method": "get_system_info",
+ "params": {
+ "api_h": "o8VEJEOd"
+ }
+}
+
+'Response':
+
+{
+ "id": "kn92anod",
+ "jsonrpc": "2.0",
+ "result": {
+ "core_type": "Intel(R) Xeon(R) CPU E5-2667 v3 @ 3.20GHz",
+ "dp_core_count": 1,
+ "dp_core_count_per_port": 1,
+ "hostname": "csi-trex-11",
+ "port_count": 2,
+ "ports": [
+ {
+ "description": "VMXNET3 Ethernet Controller",
+ "driver": "rte_vmxnet3_pmd",
+ "dst_macaddr": "00:0c:29:2a:99:bc",
+ "hw_macaddr": "00:0c:29:2a:99:b2",
+ "index": 0,
+ "is_fc_supported": false,
+ "is_led_supported": false,
+ "is_link_supported": false,
+ "is_virtual": true,
+ "numa": -1,
+ "pci_addr": "0000:03:00.0",
+ "rx": {
+ "caps": [
+ "flow_stats",
+ "latency",
+ "rx_bytes"
+ ],
+ "counters": 127
+ },
+ "speed": 10,
+ "src_macaddr": "00:0c:29:2a:99:b2",
+ "supp_speeds": [
+ 10000
+ ]
+ },
+ {
+ "description": "VMXNET3 Ethernet Controller",
+ "driver": "rte_vmxnet3_pmd",
+ "dst_macaddr": "00:0c:29:2a:99:b2",
+ "hw_macaddr": "00:0c:29:2a:99:bc",
+ "index": 1,
+ "is_fc_supported": false,
+ "is_led_supported": false,
+ "is_link_supported": false,
+ "is_virtual": true,
+ "numa": -1,
+ "pci_addr": "0000:0b:00.0",
+ "rx": {
+ "caps": [
+ "flow_stats",
+ "latency",
+ "rx_bytes"
+ ],
+ "counters": 127
+ },
+ "speed": 10,
+ "src_macaddr": "00:0c:29:2a:99:bc",
+ "supp_speeds": [
+ 10000
+ ]
+ }
+ ],
+ "uptime": "Oct 31 2016 @ 16:25:28"
+ }
+}
+
+
+----
+
+=== Get Port Status
+* *Name* - 'get_port_status'
+* *API Class* - 'core'
+* *Valid States* - 'all'
+* *Description* - Queries the server for status
+* *Parameters* -
+** *port_id* ['int'] - port id to query for owner
+* *Result* ['object'] - see below
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": "oveilf0n",
+ "jsonrpc": "2.0",
+ "method": "get_port_status",
+ "params": {
+ "api_h": "VGDJwdiY",
+ "port_id": 7
+ }
+}
+
+'Response':
+
+{
+ "id": "oveilf0n",
+ "jsonrpc": "2.0",
+ "result": {
+ "attr": {
+ "fc": {
+ "mode": 0
+ },
+ "link": {
+ "up": true
+ },
+ "promiscuous": {
+ "enabled": false
+ }
+ },
+ "max_stream_id": 3,
+ "owner": "",
+ "speed": 10000,
+ "state": "TX"
+ }
+}
+
+----
+
+.return value: 'get_port_status'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| owner | string | name of current owner (or "" if none)
+| state | string | state of port (DOWN, IDLE, STREAMS, TX, PAUSE)
+|=================
+
+
+
+=== Acquire
+* *Name* - 'Acquire'
+* *API Class* - 'core'
+* *Valid States* - 'all'
+* *Description* - Takes ownership over the port
+* *Parameters* -
+** *port_id* ['int'] - port id to take ownership
+** *user* ['string'] - User name aquiring the system
+** *force* ['boolean'] - force action even if another user is holding the port
+* *Result* ['string'] - handler for future sessions
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": "b1tr56yz",
+ "jsonrpc": "2.0",
+ "method": "Acquire",
+ "params": {
+ "api_h": "SPhoCDIV",
+ "user": "itay",
+ "port_id": 1,
+ "force": false,
+ }
+}
+
+
+'Response':
+
+{
+ "id": "b1tr56yz",
+ "jsonrpc": "2.0",
+ "result": "AQokC3ZA"
+}
+
+----
+
+
+=== Release
+* *Name* - 'release'
+* *API Class* - 'core'
+* *Valid States* - 'owned'
+* *Description* - Release owernship over the device
+* *Parameters* -
+** *handler* ['string'] - unique connection handler
+** *port_id* ['int'] - port id to release
+* *Result* ['object'] - {}
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": "m785dxwd",
+ "jsonrpc": "2.0",
+ "method": "release",
+ "params": {
+ "api_h": "SPhoCDIV",
+ "handler": "37JncCHr",
+ "port_id": 1
+ }
+}
+
+
+'Response':
+
+{
+ "id": "m785dxwd",
+ "jsonrpc": "2.0",
+ "result": {}
+}
+----
+
+
+=== Add Stream
+
+* *Name* - 'add_stream'
+* *API Class* - 'core'
+* *Valid States* - 'owned'
+* *Description* - Adds a stream to a port
+* *Parameters*
+** *handler* ['string'] - unique connection handler
+** *port_id* ['int'] - port id associated with this stream
+** *stream_id* ['int'] - stream id associated with the stream object
+** *stream* - object of type xref:stream_obj['stream']
+* *Result* ['object'] - {}
+
+
+The object type 'stream' anchor:stream_obj[]
+
+Add_stream gets a single parameter of type object.
+
+The format of that object is as follows:
+
+.Object type 'stream'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| enabled | boolean | is this stream enabled
+| self_start | boolean | is this stream triggered by starting injection or triggered by another stream
+| action_count | uint16_t | In case it is bigger than zero and next stream is not -1 (set) the number of goto will be limited to this number. Maximum value is 65K. default is zero. Zero means - not limit.
+| random_seed | uint32_t | For creating reproducible tests with random number, each stream can get a seed. this field is optional. In case of zero the seed value won't be taken
+| flags | uint16_t | bit 0 (LSB) : 1 - take the src MAC from the packet instead of config file. bit 1-2 (LSB) how to set the dest MAC ( stCFG_FILE = 0, stPKT = 1,stARP = 2 )
+| isg | double | ['usec'] inter stream gap - delay time in usec until the stream is started
+| next_stream_id | int | next stream to start after this stream. -1 means stop after this stream
+| packet | object | object of type xref:packet_obj['packet']
+| mode | object | object of type xref:mode_obj['mode']
+| vm | object | array of objects of type xref:vm_obj['vm']
+| rx_stats | object | object of type xref:rx_stats_obj['rx_stats']
+|=================
+
+==== packet
+
+anchor:packet_obj[]
+
+packet contains binary and meta data
+
+.Object type 'packet'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| binary | byte array | binary dump of the packet to be used in the stream as array of bytes
+| meta | string | meta data object. opaque to the RPC server. will be passed on queries
+|=================
+
+==== mode
+
+anchor:mode_obj[]
+
+mode object can be 'one' of the following objects:
+
+.Object type 'rate'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | [''pps'',''bps_L1'',''bps_L2'',''percentage''
+| value | double | rate
+|=================
+
+
+.Object type 'mode - continuous'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | ''continuous''
+| rate | object | rate object
+|=================
+
+
+
+.Object type 'mode - single_burst'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | ''single_burst''
+| rate | object | rate object
+| total pkts | int | total packets in the burst
+|=================
+
+.Object type 'mode - multi_burst'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | ''multi_burst''
+| rate | object | rate object
+| pkts_per_burst | int | packets in a single burst
+| ibg | double | ['usec'] inter burst gap. delay between bursts in usec
+| count | int | number of bursts. ''0'' means loop forever, ''1'' will fall back to single burst
+|=================
+
+==== vm
+
+an Object that include instructions array and properties of the field engine program anchor:vm_obj[]
+
+.Object type 'packet'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| Instructions | array | list of instructional objects
+| split_by_var | string | name of the field by which to split into threads
+| Restart | boolean | restart the field engine program when stream moving from inactive->active
+|=================
+
+
+Array of VM instruction objects to be used with this stream
+Any element in the array can be one of the following object types:
+
+===== fix_checksum_hw
+
+Fix TCP/UDP and IPv4 headers using hardware assit engine
+
+.Object type 'vm - fix_checksum_hw'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | ''fix_checksum_hw''
+| l2_len | uint16 | len of L2 (e.g. 14 Ether)
+| l3_len | uint16 | len of l3 header (e.g. 20 for IP)
+| l4_type | uint16 | the type of L4 header either UDP or TCP ( L4_TYPE_UDP = 11 | L4_TYPE_TCP = 13)
+|=================
+
+===== fix_checksum_ipv4
+
+.Object type 'vm - fix_checksum_ipv4'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | ''fix_checksum_ipv4''
+| pkt_offset | uint16 | offset of the field to fix
+|=================
+
+===== flow_var
+
+.Object type 'vm - flow_var'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | ''flow_var'''
+| name | string | flow var name - this should be a unique identifier
+| size | [1,2,4,8] | size of the flow var in bytes
+| op | ['inc', 'dec', 'random'] | operation type to perform on the field
+| init_value | uint64_t as string | init value for the field
+| min_value | uint64_t as string | minimum value for the field
+| max_value | uint64_t as string | maximum value for the field
+| step | uint64_t as string | step, how much to inc or dec. 1 is the default (in case of 'random' this field is not used)
+|=================
+
+
+===== repetable_random
+
+Instruction to choose a limited number of random values from a big range
+The values could be deterministic by providing seed
+
+.Object type 'vm - flow_var'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | ''flow_var_rand_limit'''
+| name | string | flow var name - this should be a unique identifier
+| size | [1,2,4,8] | size of the var in bytes
+| limit | uint64_t as string | the number of values to choose
+| seed | uint64_t as string | seed of the random, in case there is no seed time will be taken
+| min_value | uint64_t as string | minimum value for the field
+| max_value | uint64_t as string | maximum value for the field
+|=================
+
+
+an example of tuple_flow_var variable
+
+[source,bash]
+----
+ size = 2
+ limit = 5
+ seed = 0x1234
+ min_value = 0
+ max_value = 10
+----
+
+results could be
+
+[source,bash]
+----
+7 , 8, 1 ,5, 2 , 7 , 8, 1 ,5, 2, 7 , 8, 1 ,5, 2
+----
+
+
+===== write_flow_var
+
+.Object type 'vm - write_flow_var'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | ''write_flow_var''
+| name | string | flow var name to write
+| pkt_offset | uint16 | offset at the packet to perform the write
+| add_value | int | delta to add to the field prior to writing - can be negative
+| is_big_endian | boolean | should write as big endian or little
+|=================
+
+===== trim_pkt_size
+
+.Object type 'vm - trim_pkt_size'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | ''trim_pkt_size''
+| name | string | flow var name to take the new trim packet size from. The var size should be valid packet size and less than template packet size. see `stl/udp_rand_size.yaml` for an example
+|=================
+
+
+===== tuple_flow_var
+
+.Object type 'vm - tuple_flow_var'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | ''tuple_flow_var'''
+| name | string | tuple generator name - this should be a unique identifier name.ip and name.port will be added
+| ip_min | uint32_t as string | ipv4 min ip as uint32_t e.g. 10.0.0.1
+| ip_max | uint32_t as string | ipv4 max ip as uint32_t e.g. 10.0.1.255
+| port_min | uint16_t as string | ipv4 min port as uint16_t e.g. 1025
+| port_max | uint16_t as string | ipv4 max port as uint16_t e.g. 65000
+| limit_flows | uint32_t as string | the number of flows. 0 means we will use all the ip/port min-max range
+| flags | uint16_t as string | 1 - unlimited number of flows. in case the first bit is enabled port_min and port_max is ignored and the maximum number of flows will be generated on those ips
+|=================
+
+an example of tuple_flow_var variable
+
+[source,bash]
+----
+ ip_min = 10.0.0.1
+ ip_max = 10.0.0.5
+ port_min = 1025
+ port_max = 1028
+ limit_flows = 10
+----
+
+.Results
+[options="header",cols="1,1,3"]
+|=================
+| IP | PORT | FLOW
+| 10.0.0.1 | 1025 | 1
+| 10.0.0.2 | 1025 | 2
+| 10.0.0.3 | 1025 | 3
+| 10.0.0.4 | 1025 | 4
+| 10.0.0.5 | 1025 | 5
+| 10.0.0.1 | 1026 | 6 << the port is inc here
+| 10.0.0.2 | 1026 | 7
+| 10.0.0.3 | 1026 | 8
+| 10.0.0.4 | 1026 | 9
+| 10.0.0.5 | 1026 | 10
+| 10.0.0.1 | 1025 | 1 << back to the first flow
+|=================
+
+The variable name.port and name.ip could be written to any offset in the packet (usualy to src_ip and src_port as client)
+
+===== write_mask_flow_var
+
+.Object type 'vm - write_mask_flow_var'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| type | string | ''write_mask_flow_var'''
+| name | string | flow variable name
+| pkt_offset | uint16_t as string | offset at the packet to perform the write
+| add_value | int32_t as string | delta to add to the field prior to writing - can be negative
+| pkt_cast_size | uint_t as string | size in bytes only 1,2,4 are valid
+| mask | uint32_t as string | 1 means care e.g. 0xff will write to only 8 LSB bits
+| shift | int8_t as string | Positive will shift left (multiply by x2) negative will shift right (divided by 2) e.g. 1 will multiply by 2
+| is_big_endian | boolean | should write as big endian or little
+|=================
+
+.Pseudocode
+[source,bash]
+----
+ uint32_t val=(cast_to_size)rd_from_varible("name"); # read flow-var
+ val+=m_add_value; # add value
+
+ if (m_shift>0) { # shift
+ val=val<<m_shift;
+ }else{
+ if (m_shift<0) {
+ val=val>>(-m_shift);
+ }
+ }
+
+ pkt_val=rd_from_pkt(pkt_offset) # RMW
+ pkt_val = (pkt_val & ~m_mask) | (val & m_mask)
+ wr_to_pkt(pkt_offset,pkt_val)
+----
+
+an example of tuple_flow_var variable
+
+[source,bash]
+----
+ name = "a" (varible 2 byte start 1-10 inc )
+ pkt_cast_size = 1 ( cast to uint8_t )
+ add_value = 0
+ mask = 0xf0
+ shift = 4
+ is_big_endian =1
+----
+
+.Results
+[options="header",cols="1,1,3"]
+|=================
+| var "a" | PKT- before write | PKT post write
+| 1 | 0x03 | 0x13
+| 2 | 0x03 | 0x23
+| 3 | 0x03 | 0x33
+| 4 | 0x03 | 0x43
+| 5 | 0x03 | 0x53
+|=================
+
+The use cases of this instruction is to write to a bit field (valn/mpls)
+
+
+TIP: For more information and examples on VM objects please refer to:
+link:vm_doc.html[VM examples]
+
+==== rx_stats
+
+anchor:rx_stats_obj[]
+
+Describes rx stats for the stream
+
+{zwsp} +
+
+IMPORTANT: In case rx_stats is enabled, meta data will be written in the end of the packet.
+please also consider the following constraints:
+
+===== Constrains
+* *performance* - this will have performance impact as rx packets will be examined
+* *override* - up to 10 bytes at the end of the packet will be overidden by the meta data required
+
+===== The bytes needed for activating rx_stats
+
+* *stream_id* consumes 2 bytes
+* *seq_enabled* consumes 4 bytes
+* *latency_enabled* consumes 4 bytes
+
+so if no seq or latency are enabled 2 bytes will be used.
+
+
+if seq or latency alone are enabled, 6 bytes will be used.
+
+
+if both are enabled then 10 bytes will be used.
+
+
+.Object type 'rx_stats'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| enabled | boolean | is rx_stats enabled for this stream
+| stream_id | int | stream_id for which to collect rx_stats. +
+This could be stream_id different from the stream object which contains the rx_stats object.
+| seq_enabled | boolean | should write 32 bit sequence
+| latency_enabled | boolean | should write 32 bit latency
+|=================
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": 1,
+ "jsonrpc": "2.0",
+ "method": "add_stream",
+ "params": {
+ "api_h": "SPhoCDIV",
+ "handler": "37JncCHr",
+ "port_id": 1,
+ "stream_id": 502
+ "stream": {
+ "enabled": true,
+ "isg": 4.3,
+ "mode": {
+ "rate": {
+ "type": "pps",
+ "value": 10
+ },
+
+ "total_pkts": 5000,
+ "type": "single_burst"
+ },
+ "next_stream_id": -1,
+ "packet": {
+ "binary": [
+ 4,
+ 1,
+ 255
+ ],
+ "meta": ""
+ },
+ "rx_stats": {
+ "enabled": false
+ },
+ "self_start": true,
+ }
+ }
+}
+
+'Response':
+
+{
+ "id": 1,
+ "jsonrpc": "2.0",
+ "result": {}
+}
+
+
+----
+
+This request-reply sequence demonstrate a method in which rx_stats are diabled.
+In case rx_stats feature is enabled, rx_object **must include** all rx_stats object fields as described above.
+
+
+=== Remove Stream
+
+* *Name* - 'remove_stream'
+* *API Class* - 'core'
+* *Valid States* - 'owned'
+* *Description* - Removes a stream from a port
+* *Parameters*
+** *handler* ['string'] - unique connection handler
+** *port_id* ['int'] - port assosicated with the stream.
+** *stream_id* ['int'] - stream to remove
+
+* *Result* ['object'] - {}
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": 1
+ "jsonrpc": "2.0",
+ "method": "remove_stream",
+ "params": {
+ "api_h": "SPhoCDIV",
+ "handler": "37JncCHr",
+ "port_id": 1,
+ "stream_id": 502
+ }
+}
+
+
+'Response':
+
+{
+ "id": 1
+ "jsonrpc": "2.0",
+ "result": {}
+}
+
+----
+
+=== Get Stream ID List
+* *Name* - 'get_stream_list'
+* *API Class* - 'core'
+* *Valid States* - 'unowned', 'owned', 'active'
+* *Description* - fetch all the assoicated streams for a port
+* *Parameters*
+** *handler* ['string'] - unique connection handler
+** *port_id* ['int'] - port to query for registered streams
+
+* *Result* ['array'] - array of 'stream_id'
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": 1,
+ "jsonrpc": "2.0",
+ "method": "get_stream_list",
+ "params": {
+ "api_h": "SPhoCDIV",
+ "handler": "37JncCHr",
+ "port_id": 1
+ }
+}
+
+'Response':
+
+{
+ "id": 1,
+ "jsonrpc": "2.0",
+ "result": [
+ 502,
+ 18
+ ]
+}
+
+
+----
+
+=== Get Stream
+* *Name* - 'get_stream'
+* *API Class* - 'core'
+* *Valid States* - 'unowned', 'owned', 'active'
+* *Description* - get a specific stream object
+* *Parameters*
+** *handler* ['string'] - unique connection handler
+** *port_id* ['int'] - port for the associated stream
+** *stream_id* ['int'] - the requested stream id
+
+* *Result* ['object'] - object xref:stream_obj['stream']
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": 1,
+ "jsonrpc": "2.0",
+ "method": "get_stream",
+ "params": {
+ "api_h": "SPhoCDIV",
+ "handler": "37JncCHr",
+ "port_id": 1,
+ "stream_id": 7
+ }
+}
+
+
+'Response':
+
+{
+ "id": 1,
+ "jsonrpc": "2.0",
+ "result": {
+ "stream": {
+ "enabled": true,
+ "isg": 4.3,
+ "mode": {
+ "pps": 3,
+ "type": "continuous"
+ },
+ "next_stream_id": -1,
+ "packet": {
+ "binary": [
+ 4,
+ 1,
+ 255
+ ],
+ "meta": ""
+ },
+ "self_start": true
+ }
+ }
+}
+
+----
+
+
+=== Remove All Streams
+* *Name* - 'remove_all_streams'
+* *API Class* - 'core'
+* *Valid States* - 'owned'
+* *Description* - remove all streams from a port
+* *Parameters*
+** *handler* ['string'] - unique connection handler
+** *port_id* ['int'] - port for the associated stream
+
+* *Result* ['object'] - {}
+
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": 1,
+ "jsonrpc": "2.0",
+ "method": "remove_all_streams",
+ "params": {
+ "api_h": "SPhoCDIV",
+ "handler": "37JncCHr",
+ "port_id": 2
+ }
+}
+
+'Response':
+
+{
+ "id": 1,
+ "jsonrpc": "2.0",
+ "result": {}
+}
+
+
+----
+
+
+=== Start Traffic
+* *Name* - 'start_traffic'
+* *API Class* - 'core'
+* *Valid States* - 'owned'
+* *Description* - Starts the traffic on a specific port. if traffic has already started an error will be returned
+* *Parameters*
+** *handler* ['string'] - unique connection handler
+** *port_id* ['int'] - port id on which to start traffic
+** *core_mask* ['uint64'] [*optional*] - a non zero mask to specify which cores will be active during TX, if no value is provided, the value is all bits on (MAX_UINT64)
+
+* *Result* ['object'] - {}
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": "b3llt8hs",
+ "jsonrpc": "2.0",
+ "method": "start_traffic",
+ "params": {
+ "api_h": "SPhoCDIV",
+ "handler": "37JncCHr",
+ "port_id": 3
+ "core_mask": 0xff
+ }
+
+'Response':
+
+{
+ "id": "b3llt8hs",
+ "jsonrpc": "2.0",
+ "result": {}
+}
+
+
+----
+
+=== Stop Traffic
+* *Name* - 'stop_traffic'
+* *API Class* - 'core'
+* *Valid States* - 'active'
+* *Description* - Stops the traffic on a specific port. if the port has already started nothing will happen
+* *Parameters*
+** *handler* ['string'] - unique connection handler
+** *port_id* ['int'] - port id on which to stop traffic
+
+* *Result* ['object'] - {}
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": "h2fyhni7",
+ "jsonrpc": "2.0",
+ "method": "stop_traffic",
+ "params": {
+ "api_h": "SPhoCDIV",
+ "handler": "37JncCHr",
+ "port_id": 3
+ }
+}
+
+'Response':
+
+{
+ "id": "h2fyhni7",
+ "jsonrpc": "2.0",
+ "result": {}
+}
+
+
+----
+
+
+=== Remove RX Filters
+* *Name* - 'remove_rx_filters'
+* *API Class* - 'core'
+* *Valid States* - 'owned'
+* *Description* - Post to calling stop, the client should call this function to remove
+ any RX filters that were attached.
+ this is because the server cannot know when it is safe to remove those
+ (after stop some packets might take time to get to arrive - RTT)
+* *Parameters*
+** *handler* ['string'] - unique connection handler
+** *port_id* ['int'] - port id on which to remove all RX filters
+
+* *Result* ['object'] - {}
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": "1jwrw9nx",
+ "jsonrpc": "2.0",
+ "method": "remove_rx_filters",
+ "params": {
+ "api_h": "SPhoCDIV",
+ "handler": "ywVlqZa8",
+ "port_id": 3
+ }
+}
+
+'Response':
+
+{
+ "id": "1jwrw9nx",
+ "jsonrpc": "2.0",
+ "result": {}
+}
+
+
+----
+
+=== Get Global Stats
+* *Name* - 'get_global_stats'
+* *API Class* - 'core'
+* *Valid States* - 'unowned', 'owned', 'active'
+* *Description* - Get machine global stats
+* *Parameters* - None
+
+* *Result* ['object'] - See Below
+
+.Return value of 'get_global_stats'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| state | string | server state: can be 'unowned', 'owned' or 'active'
+| cpu_util | double | DP CPU util. in %
+| tx_bps | double | total TX bits per second
+| rx_bps | double | total RX bits per second
+| tx_pps | double | total TX packets per second
+| rx_pps | double | total RX packets per second
+| total_tx_pkts | int | total TX packets
+| total_rx_pkts | int | total RX packets
+| total_tx_bytes | int | total TX bytes
+| total_rx_bytes | int | total RX bytes
+| tx_rx_error | int | total Tx/Rx errors
+|=================
+
+=== Get Port Stats
+* *Name* - 'get_port_stats'
+* *API Class* - 'core'
+* *Valid States* - 'unowned', 'owned', 'active'
+* *Description* - Get port stats
+* *Parameters*
+** *port_id* [int] - The port id for query
+
+* *Result* ['object'] - See Below
+
+
+.Return value of 'get_port_stats'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| status | string | 'down', 'idle' or 'transmitting'
+| tx_bps | double | total TX bits per second
+| rx_bps | double | total RX bits per second
+| tx_pps | double | total TX packets per second
+| rx_pps | double | total RX packets per second
+| total_tx_pkts | int | total TX packets
+| total_rx_pkts | int | total RX packets
+| total_rx_bytes | int | total TX bytes
+| total_tx_bytes | int | total RX bytes
+| tx_rx_error | int | total Tx/Rx errors
+|=================
+
+=== Get Stream Stats
+* *Name* - 'get_steram_stats'
+* *API Class* - 'core'
+* *Valid States* - 'unowned', 'owned', 'active'
+* *Description* - Get port stats
+* *Parameters*
+** *port_id* [int] - The port id for query
+** *stream_id* [int] - The stream id for query
+
+* *Result* ['object'] - See Below
+
+.Return value of 'get_stream_stats'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| tx_bps | double | total TX bits per second
+| tx_pps | double | total TX packets per second
+| total_tx_pkts | int | total TX packets
+| total_tx_bytes | int | total TX bytes
+| rx_bps | double | total RX bits per second (if 'rx_stats' enabled)
+| rx_pps | double | total RX packets per second (if 'rx_stats' enabled)
+| total_rx_pkts | int | total RX packets (if 'rx_stats' enabled)
+| total_rx_bytes | int | total RX bytes (if 'rx_stats' enabled)
+| latency | array | array of 2 ordered elements average, maximum (if 'rx_stats' enabled)
+|=================
+
+
+=== Get Utilization
+* *Name* - 'get_utilization'
+* *API Class* - 'core'
+* *Valid States* - 'all'
+* *Description* - Get the CPU and MBUFs utilization.
+* *Parameters* - None
+* *Result* ['object'] -
+** *cpu* - The CPU utilization per DP thread (in their order). Each element is array of history (most latest is first in array, interval between values is 1 sec, values are integers 0-100).
+** *mbuf_stats* - The MBUFs are per CPU socket, per bucket of sizes: 64b, 9kb etc. Each bucket is array of 2 values: first is number of free elements and second is total.
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": "vlxrc9r6",
+ "jsonrpc": "2.0",
+ "method": "get_utilization",
+ "params": {
+ "api_h": "2AIar0tl"
+ }
+}
+
+
+
+'Response':
+
+{'id': 'vlxrc9r6',
+ 'jsonrpc': '2.0',
+ 'result': {'cpu': [[30, 33, 28, 21, 30, 35, 33, 38, 29, 25, 37, 35, 31, 34, 35, 37, 26, 31, 26, 27],
+ [37, 31, 24, 21, 26, 32, 34, 36, 27, 28, 36, 33, 35, 35, 35, 36, 30, 39, 35, 40],
+ [32, 34, 25, 29, 28, 44, 37, 40, 32, 33, 38, 33, 33, 35, 33, 25, 22, 26, 27, 31],
+ [28, 33, 17, 21, 27, 36, 30, 30, 27, 25, 36, 35, 38, 43, 41, 28, 31, 32, 31, 41],
+ [27, 31, 27, 32, 26, 36, 27, 33, 30, 29, 29, 28, 30, 36, 33, 31, 26, 30, 25, 35],
+ [31, 31, 21, 24, 23, 31, 28, 33, 33, 33, 31, 21, 30, 33, 31, 23, 27, 29, 36, 36],
+ [27, 32, 38, 23, 35, 44, 38, 28, 29, 31, 38, 38, 31, 32, 32, 33, 24, 28, 29, 32],
+ [26, 26, 24, 30, 36, 36, 33, 26, 37, 24, 29, 40, 39, 37, 36, 26, 26, 25, 38, 25],
+ [27, 37, 33, 25, 28, 37, 39, 30, 31, 26, 34, 27, 37, 31, 28, 33, 36, 39, 27, 38],
+ [31, 31, 31, 26, 31, 28, 31, 35, 24, 25, 31, 24, 34, 30, 31, 35, 29, 30, 28, 30],
+ [28, 40, 24, 27, 30, 26, 34, 27, 28, 31, 41, 29, 35, 33, 35, 35, 31, 31, 30, 39],
+ [20, 34, 29, 27, 34, 25, 28, 43, 26, 26, 36, 31, 28, 36, 39, 26, 18, 24, 29, 26],
+ [26, 29, 34, 25, 26, 42, 30, 38, 30, 26, 37, 29, 43, 36, 36, 29, 27, 37, 33, 28],
+ [29, 30, 30, 27, 34, 34, 32, 34, 26, 28, 37, 28, 36, 38, 29, 35, 26, 32, 28, 37]],
+ 'mbuf_stats': {'cpu-socket-0': {'1024b': [73696, 73710],
+ '128b': [98280, 98280],
+ '2048b': [98266, 98280],
+ '256b': [73710, 73710],
+ '4096b': [1152, 1152],
+ '512b': [73710, 73710],
+ '64b': [191468, 196560],
+ '9kb': [6912, 8960]},
+ 'cpu-socket-1': {'1024b': [73696, 73710],
+ '128b': [98280, 98280],
+ '2048b': [98266, 98280],
+ '256b': [73710, 73710],
+ '4096b': [1152, 1152],
+ '512b': [73710, 73710],
+ '64b': [191429, 196560],
+ '9kb': [6912, 8960]}}}}
+
+----
+
+=== Get Xstat names
+* *Name* - 'get_port_xstats_names'
+* *API Class* - 'core'
+* *Valid States* - 'all'
+* *Description* - Get array of names of extended stats of port. List may vary per NIC type.
+* *Parameters* - port_id
+* *Result* ['object'] - See example below
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": "m348pnzr",
+ "jsonrpc": "2.0",
+ "method": "get_port_xstats_names",
+ "params": {
+ "api_h": "f682qkNJ",
+ "port_id": 0
+ }
+}
+
+'Response':
+
+{
+ "id": "m348pnzr",
+ "jsonrpc": "2.0",
+ "result": {
+ "xstats_names": [
+ "rx_good_packets",
+ "tx_good_packets",
+ "rx_good_bytes",
+ "tx_good_bytes",
+ "rx_errors",
+ "tx_errors",
+ "rx_mbuf_allocation_errors",
+ "rx_q0packets",
+ "rx_q0bytes",
+ "rx_q0errors",
+ "rx_q1packets",
+ "rx_q1bytes",
+ "rx_q1errors",
+ "tx_q0packets",
+ "tx_q0bytes",
+ "tx_q1packets",
+ "tx_q1bytes",
+ "tx_q2packets",
+ "tx_q2bytes",
+ "tx_q3packets",
+ "tx_q3bytes",
+ "rx_unicast_packets",
+ "rx_multicast_packets",
+ "rx_broadcast_packets",
+ "rx_dropped",
+ "rx_unknown_protocol_packets",
+ "tx_unicast_packets",
+ "tx_multicast_packets",
+ "tx_broadcast_packets",
+ "tx_dropped",
+ "tx_link_down_dropped",
+ "rx_crc_errors",
+ "rx_illegal_byte_errors",
+ "rx_error_bytes",
+ "mac_local_errors",
+ "mac_remote_errors",
+ "rx_length_errors",
+ "tx_xon_packets",
+ "rx_xon_packets",
+ "tx_xoff_packets",
+ "rx_xoff_packets",
+ "rx_size_64_packets",
+ "rx_size_65_to_127_packets",
+ "rx_size_128_to_255_packets",
+ "rx_size_256_to_511_packets",
+ "rx_size_512_to_1023_packets",
+ "rx_size_1024_to_1522_packets",
+ "rx_size_1523_to_max_packets",
+ "rx_undersized_errors",
+ "rx_oversize_errors",
+ "rx_mac_short_dropped",
+ "rx_fragmented_errors",
+ "rx_jabber_errors",
+ "tx_size_64_packets",
+ "tx_size_65_to_127_packets",
+ "tx_size_128_to_255_packets",
+ "tx_size_256_to_511_packets",
+ "tx_size_512_to_1023_packets",
+ "tx_size_1024_to_1522_packets",
+ "tx_size_1523_to_max_packets",
+ "rx_flow_director_atr_match_packets",
+ "rx_flow_director_sb_match_packets",
+ "tx_low_power_idle_status",
+ "rx_low_power_idle_status",
+ "tx_low_power_idle_count",
+ "rx_low_power_idle_count",
+ "rx_priority0_xon_packets",
+ "rx_priority1_xon_packets",
+ "rx_priority2_xon_packets",
+ "rx_priority3_xon_packets",
+ "rx_priority4_xon_packets",
+ "rx_priority5_xon_packets",
+ "rx_priority6_xon_packets",
+ "rx_priority7_xon_packets",
+ "rx_priority0_xoff_packets",
+ "rx_priority1_xoff_packets",
+ "rx_priority2_xoff_packets",
+ "rx_priority3_xoff_packets",
+ "rx_priority4_xoff_packets",
+ "rx_priority5_xoff_packets",
+ "rx_priority6_xoff_packets",
+ "rx_priority7_xoff_packets",
+ "tx_priority0_xon_packets",
+ "tx_priority1_xon_packets",
+ "tx_priority2_xon_packets",
+ "tx_priority3_xon_packets",
+ "tx_priority4_xon_packets",
+ "tx_priority5_xon_packets",
+ "tx_priority6_xon_packets",
+ "tx_priority7_xon_packets",
+ "tx_priority0_xoff_packets",
+ "tx_priority1_xoff_packets",
+ "tx_priority2_xoff_packets",
+ "tx_priority3_xoff_packets",
+ "tx_priority4_xoff_packets",
+ "tx_priority5_xoff_packets",
+ "tx_priority6_xoff_packets",
+ "tx_priority7_xoff_packets",
+ "tx_priority0_xon_to_xoff_packets",
+ "tx_priority1_xon_to_xoff_packets",
+ "tx_priority2_xon_to_xoff_packets",
+ "tx_priority3_xon_to_xoff_packets",
+ "tx_priority4_xon_to_xoff_packets",
+ "tx_priority5_xon_to_xoff_packets",
+ "tx_priority6_xon_to_xoff_packets",
+ "tx_priority7_xon_to_xoff_packets"
+ ]
+ }
+}
+
+----
+
+=== Get Xstat values
+* *Name* - 'get_port_xstats_values'
+* *API Class* - 'core'
+* *Valid States* - 'all'
+* *Description* - Get array of values of extended stats of port. Order of values matches the get_port_xstats_names.
+* *Parameters* - port_id
+* *Result* ['object'] - See example below
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": "tfonjtfc",
+ "jsonrpc": "2.0",
+ "method": "get_port_xstats_values",
+ "params": {
+ "api_h": "f682qkNJ",
+ "port_id": 7
+ }
+}
+
+
+'Response':
+
+{
+ "id": "tfonjtfc",
+ "jsonrpc": "2.0",
+ "result": {
+ "xstats_values": [
+ 0,
+ 0,
+ ...
+ 0,
+ 0
+ ]
+ }
+}
+
+----
+
+=== Setting port attributes
+* *Name* - 'set_port_attr'
+* *API Class* - 'core'
+* *Valid States* - 'all'
+* *Description* - Sets port attributes
+* *Parameters* -
+** *port_id* ['int'] - port to apply attributes
+** *attr* ['object'] - dictionary with attributes, each of them is optional, see below
+* *Result* ['object'] - {}
+
+.Object type 'attr'
+[options="header",cols="1,1,1,3"]
+|=================
+| Field | Subfield | Type | Description
+| link_status | up | bool | True = link up
+| promiscuous | enabled | bool | True = promiscuous enabled
+| led_status | on | bool | False = turn off LEDs
+| flow_ctrl_mode | mode | int | Flow control: 0 = none, 1 = tx, 2 = rx, 3 = full
+|=================
+
+Request example:
+
+[source,bash]
+----
+
+'Request':
+
+{
+ "id": "uuopmfln",
+ "jsonrpc": "2.0",
+ "method": "set_port_attr",
+ "params": {
+ "api_h": "f682qkNJ",
+ "attr": {
+ "flow_ctrl_mode": {
+ "mode": 1
+ },
+ "promiscuous": {
+ "enabled": true
+ }
+ },
+ "handler": "vGp4EyA5",
+ "port_id": 7
+ }
+}
+
+----
+
+== Typical Transactions Examples
+the following examples represents common scenarios.
+commands in [...] represents 'meta commands'
+and not real RPC commands such as 'repeat', 'wait' and etc.
+
+=== Init/Boot
+This sequence represents a client implementing the protocol taking ownership
+over the server and preparing to perform work
+
+==== Commands Flow
+* *ping* - Ping the server to verify the server is up
+* *get_owner* - if owner is not me or 'none' prompt to the user if he wants to force it
+* *acquire* - Ask or force for exclusive control over the server. save the 'handler' given for future commands
+* *get_version* - Verify the server is compatible with the GUI
+* *get_system_info* - Get the installed ports and cores
+* *get_stream_list* - for every port, get the list and sync the GUI
+* *get_stream* - for every stream in a port list, get the stream info and sync the GUI
+
+=== Simple Traffic With Adding/Editing Streams
+
+describes a simple scenario where a user wants to
+add or edit one or more streams to one or more ports
+
+==== Commands Flow
+* *[init]* - perform the init procedure from above
+* *[GUI add/edit streams]* - GUI provides the user a way to add or edit streams and sync them
+* *remove_all_streams* ['optional'] - remove all previous streams to start from scratch
+* *add_stream* - configure a specific port with a stream.
+* *['repeat previous']* - 'repeat' the above for how many ports and streams desired
+* *get_stream_list* ['optional'] - sanity - verify the server is synced with the GUI
+* *start_traffic* - start traffic on the specific port / all the ports
+* *get_global_stats* ['optional'] - make sure the machine is transmiting traffic
+* *['perfrom test']* - perform the required test
+* *stop_traffic* - when done, stop the traffic on the specific port / all the ports
+* *get_global_stats* ['optional'] - make sure the machine has stopped
+
+=== Logout
+
+Describes the log off from the machine
+
+==== Commands Flow
+* *stop_traffic* ['optional'] - if traffic has started - stop it
+* *get_global_stats* ['optional'] - make sure the machine has stopped
+* *remove_all_streams* ['optional'] - if you want to clear all the previous streams - use this
+* *release* - release the ownership over the device
+
+
+:numbered!:
+
+[appendix]
+Interaction Examples
+--------------------
+
+This appendix brings examples with data for the this RPC interaction. +
+
+
+<<_add_stream, add_stream>> method example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following example represents an interaction between the RPC client and the server's response.
+
+Simple single packet client request
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+On the following example, there's no VM instructions, rx_stats option is disabled and there's only a single packet which isn't connected to any other packet.
+
+[underline]#Client request#
+[source, bash]
+----
+{
+ "id" : "2bqgd2r4",
+ "jsonrpc" : "2.0",
+ "method" : "add_stream",
+ "params" : {
+ "api_h": "SPhoCDIV",
+ "handler" : "37JncCHr",
+ "port_id" : 1,
+ "stream" : {
+ "enabled" : true,
+ "isg" : 0,
+ "mode" : {
+ "rate": {
+ "type": "pps",
+ "value": 100
+ },
+ "type" : "continuous"
+ },
+ "next_stream_id" : -1,
+ "packet" : {
+ "binary" : [
+ 0,
+ 80,
+ 86,
+ 128,
+ 13,
+ ... # more packet data
+ 77,
+ 79,
+ 250,
+ 154,
+ 66
+ ],
+ "meta" : ""
+ },
+ "rx_stats" : {
+ "enabled" : false
+ },
+ "self_start" : true,
+ "vm" : []
+ },
+ "stream_id" : 0
+ }
+}
+
+----
+
+[underline]#Server's response#
+[source, bash]
+----
+{
+ "id" : "2bqgd2r4",
+ "jsonrpc" : "2.0",
+ "result" : {}
+}
+
+----
+
+
+Two linked packets with VM instructions client request
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+On the following example, a **batch request** is being issued to the server, containing two `add_stream` requests.
+
+[underline]#First request# +
+The first client request is similar to the previous example. +
+However, in this case the rx_stats object is enbaled and set to monitor ancestor's `stream_id` (which is 0 in this case).
+
+Ontop, this stream points to the next stream as the one to follow, as described under `next_stream_id` of `stream` object.
+
+[underline]#Second request# +
+In this stream the big difference is that it has VM instructions under the `vm` field of the `stream` object.
+
+Ontop, this stream is the last stream of the sequence, so `next_stream_id` of `stream` object is set to '-1'.
+
+
+[underline]#Client request#
+
+[source, bash]
+----
+[
+ {
+ "id" : "tq49f6uj",
+ "jsonrpc" : "2.0",
+ "method" : "add_stream",
+ "params" : {
+ "api_h": "SPhoCDIV",
+ "handler" : "2JjzhMai",
+ "port_id" : 3,
+ "stream" : {
+ "enabled" : true,
+ "isg" : 0,
+ "mode" : {
+ "rate": {
+ "type": "pps",
+ "value": 100
+ },
+ "type" : "continuous"
+ },
+ "next_stream_id" : 1,
+ "packet" : {
+ "binary" : [
+ 0,
+ 80,
+ 86,
+ ... # more packet data
+ 250,
+ 154,
+ 66
+ ],
+ "meta" : ""
+ },
+ "rx_stats" : {
+ "enabled" : true,
+ "latency_enabled" : false,
+ "seq_enabled" : false,
+ "stream_id" : 0
+ },
+ "self_start" : true,
+ "vm" : []
+ },
+ "stream_id" : 0
+ }
+ },
+ {
+ "id" : "2m7i5olx",
+ "jsonrpc" : "2.0",
+ "method" : "add_stream",
+ "params" : {
+ "api_h": "SPhoCDIV",
+ "handler" : "2JjzhMai",
+ "port_id" : 3,
+ "stream" : {
+ "enabled" : true,
+ "isg" : 0,
+ "mode" : {
+ "rate": {
+ "type": "pps",
+ "value": 100
+ },
+ "type" : "continuous"
+ },
+ "next_stream_id" : -1,
+ "packet" : {
+ "binary" : [
+ 0,
+ 80,
+ 86,
+ 128,
+ ... # more packet data
+ 216,
+ 148,
+ 25
+ ],
+ "meta" : ""
+ },
+ "rx_stats" : {
+ "enabled" : false
+ },
+ "self_start" : false,
+ "vm" : [
+ {
+ "init_value" : "65537",
+ "max_value" : "65551",
+ "min_value" : "65537",
+ "name" : "l3__src",
+ "op" : "inc",
+ "size" : 4,
+ "type" : "flow_var"
+ },
+ {
+ "add_value" : 1,
+ "is_big_endian" : false,
+ "name" : "l3__src",
+ "pkt_offset" : 34,
+ "type" : "write_flow_var"
+ }
+ ]
+ },
+ "stream_id" : 1
+ }
+ }
+]
+
+----
+
+[underline]#Server's response#
+[source, bash]
+----
+[
+ {
+ "id" : "tq49f6uj",
+ "jsonrpc" : "2.0",
+ "result" : {}
+ },
+ {
+ "id" : "2m7i5olx",
+ "jsonrpc" : "2.0",
+ "result" : {}
+ }
+]
+
+----
+
+
+Another Example of tuple generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+
+[source, bash]
+----
+ - name: udp_64B
+ stream:
+ self_start: True
+ packet:
+ binary: stl/udp_64B_no_crc.pcap # pcap should not include CRC
+ mode:
+ type: continuous
+ pps: 100
+ rx_stats: []
+
+ # program that define 1M flows with IP range 16.0.0.1-16.0.0.254
+ # we will create a script that do that for you
+ # this is the low level instructions
+ vm: [
+ {
+ "type" : "tuple_flow_var", # name of the command
+
+ "name" : "tuple_gen", # tuple_gen.ip tuple_gen.port can be used
+
+ "ip_min" : 0x10000001, # min ip 16.0.0.1
+ "ip_max" : 0x100000fe, # max ip 16.0.0.254
+
+ "port_min" : 1025, # min port 1025
+ "port_max" : 65500, # max port 65500
+
+ "limit_flows" : 1000000, # number of flows
+ "flags" : 0, # 1 - for unlimited
+ },
+
+ {
+ "type" : "write_flow_var", # command name
+
+ "name" : "tuple_gen.ip", # varible to write
+
+ "add_value" : 0, # no need to add value
+
+ "is_big_endian" : true, # write as big edian
+
+ "pkt_offset" : 26, # write tuple_gen.ip into ipv4.src_ip
+ },
+
+ {
+ "type" : "fix_checksum_ipv4", # fix ipv4 header checksum
+
+ "pkt_offset" : 14, # offset of ipv4 header
+
+ },
+
+ {
+ "type" : "write_flow_var", # command name
+
+ "name" : "tuple_gen.port", # varible to write
+
+ "add_value" : 0, # no need to add value
+
+ "is_big_endian" : true, # write as big edian
+
+ "pkt_offset" : 34, # write tuple_gen.port into udp.src_port
+ }
+
+ ]
+----
diff --git a/doc/trex_scapy_rpc_server-docinfo.html b/doc/trex_scapy_rpc_server-docinfo.html
new file mode 100644
index 00000000..6fb66a5e
--- /dev/null
+++ b/doc/trex_scapy_rpc_server-docinfo.html
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/doc/trex_scapy_rpc_server.asciidoc b/doc/trex_scapy_rpc_server.asciidoc
new file mode 100755
index 00000000..65d9e7b2
--- /dev/null
+++ b/doc/trex_scapy_rpc_server.asciidoc
@@ -0,0 +1,867 @@
+The TRex Scapy RPC Server
+=========================
+:Author: Itamar Raviv
+:email: trex-dev@cisco.com
+:revnumber: 1.00
+:quotes.++:
+:numbered:
+:web_server_url: https://trex-tgn.cisco.com/trex
+:local_web_server_url: csi-wiki-01:8181/trex
+:toclevels: 4
+
+include::trex_ga.asciidoc[]
+
+== Change log
+
+[options="header",cols="^1,^h,3a"]
+|=================
+| Version | name | meaning
+| 1.00 | Itamar Raviv (itraviv) |
+- first version
+| 2.00 | Anton (XORED) | update by xored software
+|=================
+
+
+== Audience of this document
+
+TRex GUI guys
+
+== Scapy RPC Server - Overview
+Scapy Server is implemented following the link:http://www.jsonrpc.org/specification[JSON-RPC 2.0 specification], +
+Therefore, requests and replies follow the JSON-RPC 2.0 spec. +
+The server operates on a Request-Response basis *over ZMQ*, and does not support batched commands handling. +
+
+Read more about ZMQ link:http://zguide.zeromq.org/page:all[here]
+
+image::images/scapy_json_rpc_server.png[title="Scapy JSON RPC Server",align="left",width=800, link="images/scapy_json_rpc_server.png"]
+
+=== Error Codes
+
+Error codes are given according to this table: [also follows the JSON-RPC spec, with added error codes]
+
+[options="header",cols="^1,^h,3a"]
+|=================
+| Error Code | Message | Meaning
+| -32700 | Parse Error | Invalid JSON was received by the server. An error occurred on the server while parsing the JSON input.
+| -32600 | Invalid Request | The JSON sent is not a valid Request object.
+| -32601 | Method not found | The method does not exist / is not available
+| -32603 | Invalid params | Invalid method parameter(s)
+| -32097 | Syntax Error | Syntax Error in input
+| -32098 | Scapy Server: message | Scapy Server had an error while executing your command, described in the message given
+| -32096 | Scapy Server: Unknown Error | Scapy Server encountered an error that cannot be described
+
+
+|=================
+
+
+
+== Data Bases and Data Structures used in Scapy Server
+=== build_pkt, reconstruct_pkt packet model [[build_pkt_input]]
+
+Following JSON represents a Scapy structure, which can be used to build packet from scratch(build_pkt) or to modify particular fields in the prococol(reconstruct_pkt). Most fields can be omitted, in this case default or calculated values will be used.
+For reconstruct_pkt default values will be taken from the original packet.
+
+Exaples of JSON payloads and their scapy expression alternatives
+
+[source,python]
+----
+Ether(src="de:ad:be:ef:de:ad")/Dot1Q()/Dot1Q(vtype=1)/IP(src="127.0.0.1", chksum="0x312")/TCP(sport=443)
+----
+
+[source,python]
+----
+[
+ { "id": "Ether", "fields": [{"id": "src", "value": "de:ad:be:ef:de:ad"}] },
+ { "id": "Dot1Q"},
+ { "id": "Dot1Q", "fields": [{"id": "vtype", "value": "1"}] },
+ { "id": "IP", "fields": [{"id": "src", "value": "127.0.0.1"}, {"id": "chksum", "value": "0x312"}] },
+ { "id": "TCP", "fields": [{"id": "sport", "value": "443"}] }
+]
+----
+
+=== Scapy server value types
+Most values can be passed as strings(including decimal numbers, hex numbers, enums, values),
+but for binary payload, value object should be used
+
+[source,python]
+----
+- int/long/str - they can de specified directly as a value of a field
+- {"vtype": "BYTES", "base64": "my_payload_base64"} - binary payload passed as base64
+- {"vtype": "EXPRESSION", "expr": "TCPOptions()"} - python expression(normally, should be avoided)
+- {"vtype": "UNDEFINED"} - unset field value, and let it be assigned automatically
+- {"vtype": "RANDOM"} - assign a random value to a field
+----
+
+Example of object value usage(to specify binary payload)
+----
+Ether()/IP()/TCP()/Raw(load=my_payload)
+----
+
+[source,python]
+----
+[
+ { "id": "Ether"},
+ { "id": "IP"},
+ { "id": "TCP"},
+ { "id": "Raw", "fields": [
+ {
+ "id": "load",
+ "value": {"vtype": "BYTES", "base64": "my_payload_base64"}
+ }
+ ]}
+]
+----
+
+=== Scapy packet result payload [[build_pkt_output]]
+build_pkt and reconstruct pkt take packet model and produce result JSON,
+with the binary payload and field values and offsets defined
+
+[source,python]
+----
+{
+ "binary": "AAAAAQAAAAAAAgAACABFAAAoAAEAAEAGOs4QAAABMAAAAQAUAFAAAAAAAAAAAFACIABPfQAA", // base64 encoded binary payload
+ "data": [
+ {
+ "id": "Ether", # scapy class
+ "name": "Ethernet", # human-readable protocol name
+ "offset": 0, # global offset for all fields
+ "fields": [
+ {
+ "id": "dst", # scapy field id
+ "hvalue": "00:00:00:01:00:00", # human readable value
+ "length": 6, # 6 bytes
+ "offset": 0, # 0 bytes offset from
+ "value": "00:00:00:01:00:00" # internal value, which for this type is the same as hvalue
+ },
+ {
+ "id": "src",
+ ... # same as for dst
+ },
+ {
+ "hvalue": "IPv4", # human-readable value
+ "id": "type",
+ "length": 2,
+ "offset": 12, #
+ "value": 2048 # integer value for IPv4(0x800)
+ }
+ ]
+ },
+ {
+ "id": "IP",
+ "name": "IP",
+ "offset": 14,
+ "fields": [
+ {
+ "hvalue": "4",
+ "id": "version",
+ "length": 0, # the length is 0, which means it is a bitfield. mask should be used to show location
+ "offset": 0, # offset from the IP.offset. it needs to be added to all fields of IP
+ "value": 4
+ },
+ {
+ "hvalue": "5",
+ "id": "ihl",
+ "length": 0, # again length is 0. that's other part of the first byte of IP
+ "offset": 0,
+ "value": 5
+ },
+ {
+ "hvalue": "0x0",
+ "id": "tos",
+ "length": 1,
+ "offset": 1,
+ "value": 0
+ },
+ {
+ "hvalue": "40",
+ "id": "len",
+ "length": 2,
+ "offset": 2,
+ "value": 40
+ },
+ {
+ "hvalue": "1",
+ "id": "id",
+ "length": 2,
+ "offset": 4,
+ "value": 1
+ },
+ {
+ "hvalue": "", # no flags are specified here. but this field can contain "US" for URG+SYN flags
+ "id": "flags",
+ "length": 0,
+ "offset": 6,
+ "value": 0
+ },
+ {
+ "hvalue": "0",
+ "id": "frag",
+ "length": 0,
+ "offset": 6,
+ "value": 0
+ },
+ {
+ "hvalue": "64",
+ "id": "ttl",
+ "length": 1,
+ "offset": 8,
+ "value": 64
+ },
+ {
+ "hvalue": "tcp", # this field is enum. enum dictionary can be obtained as a medatata for IP fields.
+ "id": "proto",
+ "length": 1,
+ "offset": 9,
+ "value": 6
+ },
+ {
+ "hvalue": "0x3ace",
+ "id": "chksum",
+ "length": 2,
+ "offset": 10,
+ "value": 15054
+ },
+ {
+ "hvalue": "[]",
+ "id": "options",
+ "length": 2,
+ "offset": 20,
+ "value": { # options can not be representted as a human string, so they are passed as an expression
+ "expr": "[]",
+ "vtype": "EXPRESSION"
+ }
+ }
+ ]
+ },
+ {
+ "id": "TCP",
+ "name": "TCP",
+ "offset": 34
+ "fields": [
+ {
+ "hvalue": "20",
+ "id": "sport",
+ "length": 2,
+ "offset": 0,
+ "value": 20
+ },
+ # .. some more TCP fields here
+ {
+ "hvalue": "{}",
+ "id": "options",
+ "ignored": true,
+ "length": 2,
+ "offset": 20,
+ "value": { # TCPOptions are represented as a python expression with tuple and binary buffers
+ "expr": "[('MSS', 1460), ('NOP', None), ('NOP', None), ('SAckOK', b'')]",
+ "vtype": "EXPRESSION"
+ }
+ }
+ ]
+ }
+ ]
+}
+
+----
+
+=== Scapy server field definitions [[get_definitions_model]]
+Scapy server can return metadata object, describing protocols and fields.
+Most values, including field types are optional in the definition.
+If field type is missing, it can be treated as a STRING.
+
+[source,python]
+----
+"protocols": [
+{
+ "id": "Ether", # scapy class
+ "name": "Ethernet", # name of the protocol
+ "fields": [
+ {
+ "id": "dst",
+ "name": "Destination", # GUI will display Destination instead of dst
+ "type": "STRING",
+ "regex": "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"
+ },
+ {
+ "id": "src",
+ "name": "Source",
+ "type": "STRING",
+ "regex": "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"
+ },
+ {
+ "values_dict": {
+ "ATMMPOA": 34892,
+ "RAW_FR": 25945,
+ "DNA_DL": 24577,
+ "ATMFATE": 34948,
+ "ATALK": 32923,
+ "BPQ": 2303,
+ "X25": 2053,
+ "PPP_DISC": 34915,
+ "DEC": 24576,
+ "n_802_1Q": 33024,
+ "PPP_SES": 34916,
+ "TEB": 25944,
+ "SCA": 24583,
+ "PPP": 34827,
+ "FR_ARP": 2056,
+ "CUST": 24582,
+ "ARP": 2054,
+ "DNA_RC": 24578,
+ "NetBEUI": 33169,
+ "AARP": 33011,
+ "DIAG": 24581,
+ "IPv4": 2048,
+ "DNA_RT": 24579,
+ "IPv6": 34525,
+ "LAT": 24580,
+ "IPX": 33079,
+ "LOOP": 36864
+ },
+ "id": "type",
+ "name": "Type"
+ "type": "ENUM"
+ }
+ ]
+},
+{
+ "id": "TCP",
+ "name": "TCP",
+ "fields": [
+ {
+ "id": "sport",
+ "name": "Source port",
+ "type": "NUMBER",
+ "min": 0, # optional min value
+ "max": 65535 # optional max value
+
+ },
+ {
+ "id": "dport",
+ "name": "Destination port",
+ "type": "NUMBER",
+ "min": 0,
+ "max": 65535
+ },
+ {
+ "id": "seq",
+ "name": "Sequence number",
+ "type": "NUMBER"
+ },
+ {
+ "id": "ack",
+ "name": "Acknowledgment number",
+ "type": "NUMBER"
+ },
+ {
+ "id": "dataofs",
+ "name": "Data offset",
+ "type": "NUMBER"
+ },
+ {
+ "id": "reserved",
+ "name": "Reserved",
+ "type": "NUMBER"
+ },
+ {
+ "id": "flags",
+ "name": "Flags",
+ "auto": false,
+ "type": "BITMASK",
+ "bits": [ # fields definition for the UI
+ {"name": "URG", "mask": 32, "values":[{"name":"Not Set", "value": 0}, {"name":"Set", "value": 32}]},
+ {"name": "ACK", "mask": 16, "values":[{"name":"Not Set", "value": 0}, {"name":"Set", "value": 16}]},
+ {"name": "PSH", "mask": 8, "values":[{"name":"Not Set", "value": 0}, {"name":"Set", "value": 8}]},
+ {"name": "RST", "mask": 4, "values":[{"name":"Not Set", "value": 0}, {"name":"Set", "value": 4}]},
+ {"name": "SYN", "mask": 2, "values":[{"name":"Not Set", "value": 0}, {"name":"Set", "value": 2}]},
+ {"name": "FIN", "mask": 1, "values":[{"name":"Not Set", "value": 0}, {"name":"Set", "value": 1}]}
+ ]
+ },
+ {
+ "id": "window",
+ "name": "Window size",
+ "type": "NUMBER"
+ },
+ {
+ "id": "chksum",
+ "name": "Checksum",
+ "auto": true,
+ "type": "NUMBER"
+ },
+ {
+ "id": "urgptr",
+ "name": "Urgent pointer",
+ "type": "NUMBER"
+ },
+ {
+ "id": "options",
+ "name": "Options",
+ "type": "EXPRESSION"
+ }
+ ]
+},
+{
+ "id": "IP",
+ "name": "Internet Protocol Version 4",
+ "fields": [
+ {
+ "id": "version", # only renaming
+ "name": "Version"
+ },
+ {
+ "id": "ihl",
+ "name": "IHL",
+ "type": "NUMBER",
+ "auto": true # calculate IHL automatically
+ },
+ {
+ "id": "tos",
+ "name": "TOS",
+ "type": "NUMBER"
+ },
+ {
+ "id": "len",
+ "name": "Total Length",
+ "type": "NUMBER",
+ "auto": true
+ },
+ {
+ "id": "id",
+ "name": "Identification",
+ "type": "NUMBER"
+ },
+ {
+ "id": "flags",
+ "name": "Flags",
+ "type": "BITMASK",
+ "min": 0,
+ "max": 8,
+ "bits": [ # bitmask definition for IP.flags
+ {"name": "Reserved", "mask": 4, "values":[{"name":"Not Set", "value": 0}, {"name":"Set", "value": 4}]},
+ {"name": "Fragment", "mask": 2, "values":[{"name":"May fragment (0)", "value": 0}, {"name":"Don't fragment (1)", "value": 2}]},
+ {"name": "More Fragments(MF)", "mask": 1, "values":[{"name":"Not Set", "value": 0}, {"name":"Set", "value": 1}]}
+ ]
+ },
+ {
+ "id": "frag",
+ "name": "Fragment offset",
+ "type": "NUMBER"
+ },
+ {
+ "id": "ttl",
+ "name": "TTL",
+ "type": "NUMBER",
+ "min": 1,
+ "max": 255
+
+ },
+ {
+ "id": "proto",
+ "name": "Protocol"
+ },
+ {
+ "id": "chksum",
+ "name": "Checksum",
+ "type": "STRING",
+ "auto": true
+ },
+ {
+ "id": "src",
+ "name": "Source address",
+ "type": "STRING",
+ "regexp": "regexp-to-check-this-field"
+ },
+ {
+ "id": "dst",
+ "name": "Destination address",
+ "regexp": "regexp-to-check-this-field"
+ },
+ {
+ "id": "options",
+ "name": "Options",
+ "type": "EXPRESSION"
+ }
+ ]
+},
+{
+ "id": "Dot1Q",
+ "name": "802.1Q",
+ "fields": [
+ {
+ "id": "prio",
+ "name": "prio"
+ "type": "NUMBER",
+ },
+ {
+ "id": "id",
+ "type": "NUMBER",
+ "name": "id"
+ },
+ {
+ "id": "vlan",
+ "type": "NUMBER",
+ "name": "vlan"
+ },
+ {
+ "values_dict": {
+ "ATMMPOA": 34892,
+ "RAW_FR": 25945,
+ "DNA_DL": 24577,
+ "ATMFATE": 34948,
+ "ATALK": 32923,
+ "BPQ": 2303,
+ "X25": 2053,
+ "PPP_DISC": 34915,
+ "DEC": 24576,
+ "n_802_1Q": 33024,
+ "PPP_SES": 34916,
+ "TEB": 25944,
+ "SCA": 24583,
+ "PPP": 34827,
+ "FR_ARP": 2056,
+ "CUST": 24582,
+ "ARP": 2054,
+ "DNA_RC": 24578,
+ "NetBEUI": 33169,
+ "AARP": 33011,
+ "DIAG": 24581,
+ "IPv4": 2048,
+ "DNA_RT": 24579,
+ "IPv6": 34525,
+ "LAT": 24580,
+ "IPX": 33079,
+ "LOOP": 36864
+ },
+ "id": "type",
+ "name": "type",
+ "type": "ENUM"
+ }
+ ]
+},
+{
+ "id": "Raw",
+ "name": "Raw",
+ "fields": [
+ {
+ "id": "load",
+ "name": "Payload",
+ "type": "BYTES"
+ }
+ ]
+}
+]
+
+]
+----
+
+
+
+== RPC Commands
+The following RPC commands are supported. Please refer to databases section for elaboration for each database.
+
+=== Supported Methods
+* *Name* - supported_methods
+* *Description* - returns the list of all supported methods by Scapy Server and their parameters
+* *Parameters* - the parameter ('all') will return *ALL* supported methods. +
+ other string delivered as parameter will return True/False if the string matches a supported method name
+* *Result* - according to input: 'all' string will return list of supported methods, otherwise will return True/False as mentioned. +
+ The returned dictionary describes for each method it's number of parameters followed by a list of their names.
+
+*Example:*
+
+[source,python]
+----
+'Request':
+{
+ "jsonrpc": "2.0",
+ "id": "1",
+ "method": "supported_methods",
+ "params": ["all"]
+}
+
+'Result':
+{'id': '1',
+ 'jsonrpc': '2.0',
+ 'result': { .
+ .
+ .
+ .
+ 'build_pkt': [1, [u'pkt_descriptor']],
+ 'check_update': [2, [u'db_md5', u'field_md5']],
+ 'get_all': [0, []],
+ 'get_tree': [0, []],
+ 'get_version': [0, []],
+ 'supported_methods': [1, [u'method_name']]
+ }
+}
+----
+
+
+
+=== GetAll
+* *Name* - 'get_all'
+* *Description* - Returns the supported protocols library (DB) and Field-to-RegEx mapping library, and their MD5
+* *Paramters* - None
+* *Result* ['object'] - JSON format of dictionary. see table below
+
+.Object type 'return values for get_all'
+[options="header",cols="1,1,3,3"]
+|=================
+| Key | Key Type | Value | Value Type
+| db | string | supported protocols dictionary | protocol dictionary
+| fields | string | Field-to-RegEx dictionary | Field-to-RegEx dictionary
+| db_md5 | string | MD5 of DB | encoded in base64
+| fields_md5 | string | MD5 of fields | encoded in base64
+|=================
+
+*Example:*
+
+[source,python]
+----
+'Request':
+{
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": "get_all",
+ "params": []
+}
+
+'Response':
+{
+ "jsonrpc" : "2.0",
+ "id" : 1,
+ "result" : {'db': {'ARP': [('hwtype', 'XShortField', '(1)'),
+ ('ptype', 'XShortEnumField', '(2048)'),
+ ('hwlen', 'ByteField', '(6)'),
+ ('plen', 'ByteField', '(4)'),
+ ('op', 'ShortEnumField', '(1)'),
+ ('hwsrc', 'ARPSourceMACField', '(None)'),
+ ('psrc', 'SourceIPField', '(None)'),
+ ('hwdst', 'MACField', "('00:00:00:00:00:00')"),
+ ('pdst', 'IPField', "('0.0.0.0')")],
+ .
+ .
+ .
+ 'db_md5': 'Z+gRt88y7SC0bDu496/DQg==\n',
+ 'fields': {'ARPSourceMACField': 'empty',
+ 'BCDFloatField': 'empty',
+ 'BitEnumField': 'empty',
+ .
+ .
+ .
+
+}
+
+----
+
+=== Check if Database is updated
+* *Name* - 'check_update'
+* *Description* - checks if both protocol database and fields database are up to date according to md5 comparison
+* *Parameters* - md5 of database, md5 of fields
+* *Result* - upon failure: error code -32098 (see link:trex_scapy_rpc_server.html#_error_codes[RPC server error codes]) +
+ followed by a message: "Fields DB is not up to date" or "Protocol DB is not up to date" +
+ upon success: return 'true' as result (see below) +
+ +
+*Example:*
+
+[source,python]
+----
+'Request':
+
+{
+ "jsonrpc": "2.0",
+ "id": "1",
+ "method": "check_update",
+ "params": ["md5_of_protocol_db", "md5_of_fields"]
+}
+
+'Response': #on failure
+
+{
+ "jsonrpc": "2.0",
+ "id": "1",
+ "error": {
+ "code": -32098,
+ "message:": "Scapy Server: Fields DB is not up to date"
+ }
+}
+
+'Response': #on success
+
+{
+ "jsonrpc": "2.0",
+ "id": "1",
+ "result": true
+}
+----
+
+
+=== Get Version
+* *Name* - 'get_version'
+* *Description* - Queries the server for version information
+* *Paramters* - None
+* *Result* ['object'] - See table below
+
+.Object type 'return values for get_version'
+[options="header",cols="1,1,3"]
+|=================
+| Field | Type | Description
+| version | string | Scapy Server version
+| built_by | string | who built this version
+|=================
+
+
+*Example:*
+[source,python]
+----
+
+'Request':
+
+{
+ "jsonrpc": "2.0",
+ "id": "1",
+ "method": "get_version",
+ "params": []
+}
+
+
+
+'Response':
+
+{
+ "jsonrpc": "2.0",
+ "id": "1",
+ "result": {
+ "version": "v1.0",
+ "built_by": "itraviv"
+ }
+}
+
+----
+
+=== Build Packet
+* *Name* - 'build_pkt'
+* *Description* - Builds a new packet from the definition and returns binary data and json structure +
+* *Return Value* - Returns xref:build_pkt_output[Scapy packet result payload].
+* *Paramters* - JSON xref:build_pkt_input[packet definition model].
+
+=== Create packet from binary data and modify fields
+* *Name* - 'reconstruct_pkt'
+* *Description* - Builds a new packet from the binary data and returns binary data and json structure +
+* *Return Value* - Returns xref:build_pkt_output[Scapy packet result payload].
+* *Paramters* - base64-encoded packet bytes, optional JSON xref:build_pkt_input[packet definition model] with fields to override.
+
+=== Get protocol definitions
+* *Name* - 'get_definitions'
+* *Description* - Returns definitions for protocols and fields +
+* *Return Value* - array of protocol definitions in a "result.protocols" json. xref:get_definitions_model[Output model]
+* *Paramters* - array of protocol class names to define or null to fetch metadata for all protocols. ex. ["Ether", "TCP"]
+
+=== Get protocol tree hierarchy example
+* *Name* - 'get_tree'
+* *Description* - returns a *suggested* dictionary of protocols ordered in a hierarchy tree. +
+User can still create non valid hierarchies. (such as Ether()/DNS()/IP())
+* *Parameters* - none
+* *Result* [dictionary] - Example for packet layers that can be used to build a packet. Ordered in an hierarchy tree.
+
+*Example:*
+
+[source,python]
+----
+
+'Request':
+
+{
+ "id": "1",
+ "jsonrpc": "2.0",
+ "method": "get_tree",
+ "params": []
+}
+
+
+'Response':
+
+{'id': '1',
+ 'jsonrpc': '2.0',
+ 'result': {'ALL': {
+ 'Ether': {'ARP': {},
+ 'IP': { 'TCP': {'RAW': 'payload'},
+ 'UDP': {'RAW': 'payload'}
+ }
+ }
+ }
+ }
+}
+----
+
+
+== Usage of Scapy RPC Server
+Notice the existance of the following files:
+
+* scapy_service.py
+* scapy_zmq_server.py
+* scapy_zmq_client.py
+
+=== Scapy_zmq_server.py
+In this section we will see how to bring up the Scapy ZMQ server.
+There are 2 ways to run this server:
+
+* Through command line
+* Through Python interpreter
+
+==== Running Scapy ZMQ Server from command line
+Run the file scapy_zmq_server.py with the argument -s to declare the port that the server will listen to. +
+Running the file without the "-s" argument will use *port 4507 by default*. +
+ +
+Notice:
+
+* The Server's IP will be the IP address of the local host.
+* The Server will accept requests from *any* IP address on that port.
+
+[source,bash]
+----
+user$ python scapy_zmq_server.py -s 5555
+
+***Scapy Server Started***
+Listening on port: 5555
+Server IP address: 10.0.0.1
+
+----
+
+==== Running Scapy ZMQ Server from the Python interpreter
+* Run the Python Interpreter (Scapy Server currently supports Python2)
+* Import the scapy_zmq_server.py file
+* Create a Scapy_server Object with argument as port number. default argument is port 4507
+* Invoke method activate(). (This method is blocking because the server is listening on the port).
+
+[source,bash]
+----
+user$ python
+>>> from scapy_zmq_server import *
+>>> s = Scapy_server() // starts with port 4507
+>>> s = Scapy_server(5555) //starts with port 5555
+>>> s.activate()
+***Scapy Server Started***
+Listening on port: 5555
+Server IP address: 10.0.0.1
+
+----
+
+==== Shutting down Scapy ZMQ Server
+There are 2 ways to shut down the server:
+
+* The server can be shut down using the keyboard interrupt Ctrl+C
+* The server can be shut down remotely with the method "shut_down" with no arguments
+
+[source,bash]
+----
+//Sending Request: {"params": [], "jsonrpc": "2.0", "method": "shut_down", "id": "1"}
+//Will result in this print by the server:
+Server: Shut down by remote user
+----
+
+
+
+
+
+
diff --git a/doc/trex_stateless-docinfo.html b/doc/trex_stateless-docinfo.html
new file mode 100755
index 00000000..a444f506
--- /dev/null
+++ b/doc/trex_stateless-docinfo.html
@@ -0,0 +1,22 @@
+
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+
+<script src="my_chart.js"></script>
+
+<style>
+.axis path,
+.axis line {
+ fill: none;
+ stroke: #000;
+ shape-rendering: crispEdges;
+}
+
+.dot {
+ stroke: #000;
+}
+</style>
+
+
+
+
+
diff --git a/doc/trex_stateless.asciidoc b/doc/trex_stateless.asciidoc
new file mode 100755
index 00000000..419df9b3
--- /dev/null
+++ b/doc/trex_stateless.asciidoc
@@ -0,0 +1,4306 @@
+TRex Stateless support
+======================
+:author: TRex team
+:email: trex.tgen@gmail.com
+:revnumber: 2.01
+:quotes.++:
+:numbered:
+:web_server_url: https://trex-tgn.cisco.com/trex
+:local_web_server_url: csi-wiki-01:8181/trex
+:github_stl_path: https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/stl
+:github_stl_examples_path: https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/automation/trex_control_plane/stl/examples
+:toclevels: 6
+
+include::trex_ga.asciidoc[]
+
+// PDF version - image width variable
+ifdef::backend-docbook[]
+:p_width: 450
+:p_width_1: 200
+:p_width_1a: 100
+:p_width_1c: 150
+:p_width_lge: 500
+endif::backend-docbook[]
+
+// HTML version - image width variable
+ifdef::backend-xhtml11[]
+:p_width: 800
+:p_width_1: 400
+:p_width_1a: 650
+:p_width_1a: 400
+:p_width_lge: 900
+endif::backend-xhtml11[]
+
+
+
+== Audience
+
+This document assumes basic knowledge of TRex, and assumes that TRex is installed and configured.
+For information, see the link:trex_manual.html[manual], especially the material up to the link:trex_manual.html#_basic_usage[Basic Usage] section.
+
+== Stateless support (Beta stage)
+
+=== High level functionality
+// maybe Feature overview
+
+* Large scale - Supports about 10-22 million packets per second (mpps) per core, scalable with the number of cores
+* Support for 1, 10, 25, 40, and 100 Gb/sec interfaces
+* Support for multiple traffic profiles per interface
+* Profile can support multiple streams, scalable to 10K parallel streams
+* Supported for each stream:
+** Packet template - ability to build any packet (including malformed) using link:https://en.wikipedia.org/wiki/Scapy[Scapy] (example: MPLS/IPv4/Ipv6/GRE/VXLAN/NSH)
+** Field engine program
+*** Ability to change any field inside the packet (example: src_ip = 10.0.0.1-10.0.0.255)
+*** Ability to change the packet size (example: random packet size 64-9K)
+** Mode - Continuous/Burst/Multi-burst support
+** Rate can be specified as:
+*** Packets per second (example: 14MPPS)
+*** L1 bandwidth (example: 500Mb/sec)
+*** L2 bandwidth (example: 500Mb/sec)
+*** Interface link percentage (example: 10%)
+** Support for HLTAPI-like profile definition
+** Action - stream can trigger a stream
+* Interactive support - Fast Console, GUI
+* Statistics per interface
+* Statistics per stream done in hardware
+* Latency and Jitter per stream
+* Blazingly fast automation support
+** Python 2.7/3.0 Client API
+** Python HLTAPI Client API
+* Multi-user support - multiple users can interact with the same TRex instance simultaneously
+
+
+==== Traffic profile example
+
+The following example shows three streams configured for Continuous, Burst, and Multi-burst traffic.
+
+image::images/stl_streams_example_02.png[title="Example of multiple streams",align="left",width={p_width}, link="images/stl_streams_example_02.png"]
+
+==== High level functionality - near future
+
+// "near future" and "roadmap" (below) are ~ same. Typically, Cisco does not document features before they're ready, but open source is a little different. We might want to find a better place to put the roadmap for the future - maybe a separate document.
+
+* ARP emulation - learn server MAC. Support unlimited MAC addresses per port.
+
+==== High level functionality - Roadmap for future development
+
+* Add emulation support
+** RIP/BGP/ISIS/SPF
+
+
+=== IXIA IXExplorer vs TRex
+
+TRex has limited functionality compared to IXIA, but has some advantages. The following table summarizes the differences:
+
+.TRex vs IXExplorer
+[cols="1^,3^,3^,5^", options="header"]
+|=================
+| Feature | IXExplorer |TRex | Description
+| Line rate | Yes | 10-24MPPS/core, depends on the use case |
+| Multi stream | 255 | [green]*Unlimited* |
+| Packet build flexibility | Limited | [green]*Scapy - Unlimited* | Example: GRE/VXLAN/NSH is supported. Can be extended to future protocols
+| Packet Field engine | limited | [green]*Unlimited* |
+| Tx Mode | Continuous/Burst/Multi-burst | Continuous/Burst/Multi-burst|
+| ARP Emulation | Yes | Not yet - workaround |
+| Automation | TCL/Python wrapper to TCL | [green]*native Python/Scapy* |
+| Automation speed sec| 30 sec | [green]*1 msec* | Test of load/start/stop/get counters
+| HLTAPI | Full support. 2000 pages of documentation | Limited. 20 pages of documentation|
+| Per Stream statistics | 255 streams with 4 global masks | 128 rules for XL710/X710 hardware and software impl for 82599/I350/X550| Some packet type restrictions apply to XL710/X710.
+| Latency Jitter | Yes,Resolution of nsec (hardware) | Yes,Resolution of usec (software) |
+| Multi-user support | Yes | Yes |
+| GUI | very good | WIP, packet build is scapy-based. Not the same as IXIA. Done by Exalt |
+| Cisco pyATS support | Yes | Yes - Python 2.7/Python 3.4 |
+| Emulation | Yes | Not yet |
+| Port IDs | Based on IXIA numebrs | Depends on PCI enumeration
+|=================
+
+
+=== RPC Architecture
+
+A JSON-RPC2 thread in the TRex control plane core provides support for interactive mode.
+
+// RPC = Remote Procedure Call, alternative to REST? --YES, no change
+
+image::images/trex_architecture_01.png[title="RPC Server Components",align="left",width={p_width}, link="images/trex_architecture_01.png"]
+
+// OBSOLETE: image::images/trex_2_stateless.png[title="RPC Server Components",align="left",width={p_width}, link="images/trex_2_stateless.png"]
+
+// Is there a big picture that would help to make the next 11 bullet points flow with clear logic? --explanation of the figure
+
+*Layers*::
+* Control transport protocol: ZMQ working in REQ/RES mode.
+// change all ZMQ to "link:http://rfc.zeromq.org/spec:37[ZeroMQ] Message Transport Protocol (ZMTP)"? not sure what REQ/RES mode is
+* RPC protocol on top of the control transport protocol: JSON-RPC2.
+* Asynchronous transport: ZMQ working in SUB/PUB mode (used for asynchronous events such as interface change mode, counters, and so on).
+
+// TBD: rendering problem with bullet indentation
+// Maybe Layers, Interfaces, and Control of Interfaces should each be level 4 headings instead of complex bulleted lists.
+
+
+
+*Interfaces*::
+* Automation API: Python is the first client to implement the Python automation API.
+* User interface: The console uses the Python API to implement a user interface for TRex.
+* GUI : The GUI works on top of the JSON-RPC2 layer.
+
+*Control of TRex interfaces*::
+* Numerous users can control a single TRex server together, from different interfaces.
+* Users acquire individual TRex interfaces exclusively. *Example*: Two users control a 4-port TRex server. User A acquires interfaces 0 and 1; User B acquires interfaces 3 and 4.
+* Only one user interface (console or GUI) can have read/write control of a specific interface. This enables caching the TRex server interface information in the client core. *Example*: User A, with two acquired interfaces, can have only one read/write control session at a time.
+* A user can set up numerous read-only clients on a single interface - for example, for monitoring traffic statistics on the interface.
+* A client in read-write mode can acquire a statistic in real time (with ASYNC ZMQ). This enables viewing statistics through numerous user interfaces (console and GUI) simultaneously.
+
+*Synchronization*::
+* A client syncs with the TRex server to get the state in connection time, and caches the server information locally after the state has changed.
+* If a client crashes or exits, it syncs again after reconnecting.
+
+image::images/trex_stateless_multi_user_02.png[title="Multiple users, per interface",align="left",width={p_width}, link="images/trex_stateless_multi_user_02.png"]
+
+For details about the TRex RPC server, see the link:trex_rpc_server_spec.html[RPC specification].
+
+==== RPC architecture highlights
+
+This Architecture provides the following advantages:
+
+* Fast interaction with TRex server. Loading, starting, and stopping a profile for an interface is very fast - about 2000 cycles/sec.
+* Leverages Python/Scapy for building a packet/field engine.
+* HLTAPI compiler complexity is handled in Python.
+
+=== TRex Objects
+
+// maybe call it "Objects" in title and figure caption
+
+image::images/stateless_objects_02.png[title="TRex Objects",align="left",width={p_width_1}, link="images/stateless_objects_02.png"]
+
+* *TRex*: Each TRex instance supports numerous interfaces.
+// "one or more"?
+* *Interface*: Each interface supports one or more traffic profiles.
+* *Traffic profile*: Each traffic profile supports one or more streams.
+* *Stream*: Each stream includes:
+** *Packet*: Packet template up to 9 KB
+// ok to standardize to KB?
+** *Field Engine*: Which field to change, do we want to change packet size
+// unclear
+** *Mode*: Specifies how to send packets: Continuous/Burst/Multi-burst
+** *Rx Stats*: Statistics to collect for each stream
+** *Rate*: Rate (packets per second or bandwidth)
+** *Action*: Specifies stream to follow when the current stream is complete (valid for Continuous or Burst modes).
+
+
+=== Stateful vs Stateless
+
+TRex Stateless support enables basic L2/L3 testing, relevant mostly for a switch or router. Using Statelss mode, it is possible to define a stream with a *one* packet template, define a program to change any fields in the packet, and run the stream in continuous, burst, or multi-burst mode.
+With Stateless, you *cannot* learn NAT translation; there is no context of flow/client/server.
+
+* In Stateful mode, the basic building block is a flow/application (composed of many packets).
+* Stateless mode is much more flexible, enabling you to define any type of packet, and build a simple program.
+
+.Stateful vs Stateless features
+[cols="1^,3^,3^", options="header"]
+|=================
+| Feature | Stateless |Stateful
+| Flow base | No | Yes
+| NAT | No | Yes
+| Tunnel | Yes | Some are supported
+| L7 App emulation | No | Yes
+| Any type of packet | Yes | No
+| Latency Jitter | Per Stream | Global/Per flow
+|=================
+
+==== Using Stateless mode to mimic Stateful mode
+
+Stateless mode can mimic some, but not all functionality of Stateful mode.
+For example, you can load a pcap with the number of packets as a link of streams:
+a->b->c->d-> back to a
+You can then create a program for each stream to change src_ip=10. 0.0.1-10.0.0.254. This creates traffic similar to that of Stateful mode, but with a completely different basis.
+
+If you are confused you probably need Stateless. :-)
+
+=== TRex package folders
+
+[cols="5,5", options="header",width="100%"]
+|=============================
+| Location | Description
+| / | t-rex-64/dpdk_set_ports/stl-sim
+| /stl | Stateless native (py) profiles
+| /stl/yaml | Stateless YAML profiles
+| /stl/hlt | Stateless HLT profiles
+| /ko | Kernel modules for DPDK
+| /external_libs | Python external libs used by server/clients
+| /exp | Golden pcap file for unit-tests
+| /cfg | Examples of config files
+| /cap2 | Stateful profiles
+| /avl | Stateful profiles - SFR profile
+| /automation | Python client/server code for both Stateful and Stateless
+| /automation/regression | Regression for Stateless and Stateful
+| /automation/config | Regression setups config files
+| /automation/trex_control_plane/stl | Stateless lib and Console
+| /automation/trex_control_plane/stl/trex_stl_lib | Stateless lib
+| /automation/trex_control_plane/stl/examples | Stateless Examples
+|=============================
+
+=== Tutorials
+
+The tutorials in this section demonstrate basic TRex *stateless* use cases. Examples include common and moderately advanced TRex concepts.
+
+==== Tutorial: Simple IPv4/UDP packet - TRex
+
+*Goal*::
+
+Send a simple UDP packet from all ports of a TRex server.
+
+*Traffic profile*::
+
+The following profile defines one stream, with an IP/UDP packet template with 10 bytes of 'x'(0x78) of payload. For more examples of defining packets using Scapy see the link:http://www.secdev.org/projects/scapy/doc/[Scapy documentation].
+
+*File*::
+
+link:{github_stl_path}/udp_1pkt_simple.py[stl/udp_1pkt_simple.py]
+
+[source,python]
+----
+from trex_stl_lib.api import *
+
+class STLS1(object):
+
+ def create_stream (self):
+
+ return STLStream(
+ packet =
+ STLPktBuilder(
+ pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/
+ UDP(dport=12,sport=1025)/(10*'x') <1>
+ ),
+ mode = STLTXCont()) <2>
+
+
+ def get_streams (self, direction = 0, **kwargs): <3>
+ # create 1 stream
+ return [ self.create_stream() ]
+
+
+# dynamic load - used for TRex console or simulator
+def register(): <4>
+ return STLS1()
+----
+<1> Defines the packet. In this case, the packet is IP/UDP with 10 bytes of 'x'. For more information, see the link:http://www.secdev.org/projects/scapy/doc/[Scapy documentation].
+<2> Mode: Continuous. Rate: 1 PPS (default rate is 1 PPS)
+<3> The `get_streams` function is mandatory
+<4> Each traffic profile module requires a `register` function.
+
+[NOTE]
+=====================================================================
+The SRC/DST MAC addresses are taken from /etc/trex_cfg.yaml. To change them, add Ether(dst="00:00:dd:dd:00:01") with the desired destination.
+=====================================================================
+
+
+*Start TRex as a server*::
+
+[NOTE]
+=====================================================================
+The TRex package includes all required packages. It is unnecessary to install any python packages (including Scapy).
+=====================================================================
+
+[source,bash]
+----
+$sudo ./t-rex-64 -i
+----
+
+* Wait until the server is up and running.
+* (Optional) Use `-c` to add more cores.
+* (Optional) Use `--cfg` to specify a different configuration file. The default is link:trex_manual.html#_create_minimum_configuration_file[/etc/trex_cfg.yaml].
+
+// IGNORE: this line helps rendering of next line
+
+*Connect with console*::
+
+On the same machine, in a new terminal window (open a new window using `xterm`, or `ssh` again), connect to TRex using `trex-console`.
+
+[source,bash]
+----
+$trex-console #<1>
+
+Connecting to RPC server on localhost:4501 [SUCCESS]
+connecting to publisher server on localhost:4500 [SUCCESS]
+Acquiring ports [0, 1, 2, 3]: [SUCCESS]
+
+125.69 [ms]
+
+trex>start -f stl/udp_1pkt_simple.py -m 10mbps -a #<2>
+
+Removing all streams from port(s) [0, 1, 2, 3]: [SUCCESS]
+Attaching 1 streams to port(s) [0, 1, 2, 3]: [SUCCESS]
+Starting traffic on port(s) [0, 1, 2, 3]: [SUCCESS]
+
+# pause the traffic on all port
+>pause -a #<3>
+
+# resume the traffic on all port
+>resume -a #<4>
+
+# stop traffic on all port
+>stop -a #<5>
+
+# show dynamic statistic
+>tui
+----
+<1> Connects to the TRex server from the local machine.
+<2> Start the traffic on all ports at 10 mbps. Can also specify as MPPS. Example: 14 MPPS (`-m 14mpps`).
+<3> Pauses the traffic.
+<4> Resumes.
+<5> Stops traffic on all the ports.
+
+
+[NOTE]
+=====================================================================
+If you have a connection *error*, open the /etc/trex_cfg.yaml file and remove keywords such as `enable_zmq_pub : true` and `zmq_pub_port : 4501` from the file.
+=====================================================================
+
+*Viewing streams*::
+
+To display stream data for all ports, use `streams -a`.
+
+.Streams
+[source,bash]
+----
+trex>streams -a
+Port 0:
+
+ ID | packet type | length | mode | rate | next stream
+ -----------------------------------------------------------------------------------
+ 1 | Ethernet:IP:UDP:Raw | 56 | Continuous | 1.00 pps | -1
+
+Port 1:
+
+ ID | packet type | length | mode | rate | next stream
+ -----------------------------------------------------------------------------------
+ 1 | Ethernet:IP:UDP:Raw | 56 | Continuous | 1.00 pps | -1
+
+Port 2:
+
+ ID | packet type | length | mode | rate | next stream
+ -----------------------------------------------------------------------------------
+ 1 | Ethernet:IP:UDP:Raw | 56 | Continuous | 1.00 pps | -1
+
+Port 3:
+
+ ID | packet type | length | mode | rate | next stream
+ -----------------------------------------------------------------------------------
+ 1 | Ethernet:IP:UDP:Raw | 56 | Continuous | 1.00 pps | -1
+----
+
+
+*Viewing command help*::
+
+
+To view help for a command, use `<command> --help`.
+
+*Viewing general statistics*::
+
+To view general statistics, open a "textual user interface" with `tui`.
+
+[source,bash]
+----
+TRex >tui
+Global Statistics
+
+Connection : localhost, Port 4501
+Version : v1.93, UUID: N/A
+Cpu Util : 0.2%
+ :
+Total Tx L2 : 40.01 Mb/sec
+Total Tx L1 : 52.51 Mb/sec
+Total Rx : 40.01 Mb/sec
+Total Pps : 78.14 Kpkt/sec
+ :
+Drop Rate : 0.00 b/sec
+Queue Full : 0 pkts
+
+Port Statistics
+
+ port | 0 | 1 |
+ --------------------------------------------------------
+ owner | hhaim | hhaim |
+ state | ACTIVE | ACTIVE |
+ -- | | |
+ Tx bps L2 | 10.00 Mbps | 10.00 Mbps |
+ Tx bps L1 | 13.13 Mbps | 13.13 Mbps |
+ Tx pps | 19.54 Kpps | 19.54 Kpps |
+ Line Util. | 0.13 % | 0.13 % |
+ --- | | |
+ Rx bps | 10.00 Mbps | 10.00 Mbps |
+ Rx pps | 19.54 Kpps | 19.54 Kpps |
+ ---- | | |
+ opackets | 1725794 | 1725794 |
+ ipackets | 1725794 | 1725794 |
+ obytes | 110450816 | 110450816 |
+ ibytes | 110450816 | 110450816 |
+ tx-bytes | 110.45 MB | 110.45 MB |
+ rx-bytes | 110.45 MB | 110.45 MB |
+ tx-pkts | 1.73 Mpkts | 1.73 Mpkts |
+ rx-pkts | 1.73 Mpkts | 1.73 Mpkts |
+ ----- | | |
+ oerrors | 0 | 0 |
+ ierrors | 0 | 0 |
+
+ status: /
+
+ browse: 'q' - quit, 'g' - dashboard, '0-3' - port display
+ dashboard: 'p' - pause, 'c' - clear, '-' - low 5%, '+' - up 5%,
+----
+
+
+*Discussion*::
+
+In this example TRex sends the *same* packet from all ports. If your setup is connected with loopback, you will see Tx packets from port 0 in Rx port 1 and vice versa. If you have DUT with static route, you might see all the packets going to specific port.
+
+.Static route
+[source,bash]
+----
+interface TenGigabitEthernet0/0/0
+ mtu 9000
+ ip address 1.1.9.1 255.255.255.0
+!
+interface TenGigabitEthernet0/1/0
+ mtu 9000
+ ip address 1.1.10.1 255.255.255.0
+!
+
+ip route 16.0.0.0 255.0.0.0 1.1.9.2
+ip route 48.0.0.0 255.0.0.0 1.1.10.2
+----
+
+// this is good info, but it isn't organized into specific tasks or explanations of specific goals. so comes across as useful but somewhat random. for example in the Static route example above, we should explain at the beginning that this will route all packets to one port, and that the next example will demonstrate how to route the packets to different ports.
+
+In this example all the packets will be routed to `TenGigabitEthernet0/1/0` port. The following example uses the `direction` flag to change this.
+
+*File*:: link:{github_stl_path}/udp_1pkt_simple_bdir.py[stl/udp_1pkt_simple_bdir.py]
+
+[source,python]
+----
+
+ class STLS1(object):
+
+ def create_stream (self):
+ return STLStream(
+ packet =
+ STLPktBuilder(
+ pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/
+ UDP(dport=12,sport=1025)/(10*'x')
+ ),
+ mode = STLTXCont())
+
+ def get_streams (self, direction = 0, **kwargs):
+ # create 1 stream
+ if direction==0: <1>
+ src_ip="16.0.0.1"
+ dst_ip="48.0.0.1"
+ else:
+ src_ip="48.0.0.1"
+ dst_ip="16.0.0.1"
+
+ pkt = STLPktBuilder(
+ pkt = Ether()/IP(src=src_ip,dst=dst_ip)/
+ UDP(dport=12,sport=1025)/(10*'x') )
+
+ return [ STLStream( packet = pkt,mode = STLTXCont()) ]
+----
+<1> This use of the `direction` flag causes a different packet to be sent for each direction.
+
+
+==== Tutorial: Connect from a remote server
+
+*Goal*:: Connect by console from remote machine to a TRex server
+
+*Check that TRex server is operational*::
+
+Ensure that the TRex server is running. If not, run TRex in interactive mode.
+// again, this is a bit vague. the tutorial should provide simple steps for using interactive mode or not. too many conditions.
+
+[source,bash]
+----
+$sudo ./t-rex-64 -i
+----
+
+*Connect with Console*::
+
+From a remote machine, use `trex-console` to connect. Include the `-s` flag, as shown below, to specify the server.
+
+[source,bash]
+----
+$trex-console -s csi-kiwi-02 #<1>
+----
+<1> TRex server is csi-kiwi-02.
+
+The TRex client requires Python versions 2.7.x or 3.4.x. To change the Python version, set the *PYTHON* environment variable as follows:
+
+.tcsh shell
+[source,bash]
+----
+setenv PYTHON /bin/python #tcsh
+----
+
+.bash shell
+[source,bash]
+----
+extern PYTHON=/bin/mypython #bash
+----
+
+[NOTE]
+=====================================================================
+The client machine should run Python 2.7.x or 3.4.x. Cisco CEL/ADS is supported. The TRex package includes the required link:cp_stl_docs/[client archive].
+=====================================================================
+
+==== Tutorial: Source and Destination MAC addresses
+
+*Goal*:: Change the source/destination MAC address
+
+Each TRex port has a source and destination MAC (DUT) configured in the /etc/trex_cfg.yaml configuration file. The source MAC is not necessarily the hardware MAC address configured in EEPROM. By default, the hardware-specified MAC addresses (source and destination) are used. If a source or destination MAC address is configured explicitly, that address takes precedence over the hardware-specified default.
+
+.MAC address
+[format="csv",cols="2^,2^,2^", options="header",width="100%"]
+|=================
+Scapy , Source MAC,Destination MAC
+Ether() , trex_cfg (src),trex_cfg(dst)
+Ether(src="00:bb:12:34:56:01"),"00:bb:12:34:56:01",trex_cfg(dst)
+Ether(dst="00:bb:12:34:56:01"),trex_cfg(src),"00:bb:12:34:56:01"
+|=================
+
+
+*File*:: link:{github_stl_path}/udp_1pkt_1mac_override.py[stl/udp_1pkt_1mac_override.py]
+
+[source,python]
+----
+ def create_stream (self):
+
+ base_pkt = Ether(src="00:bb:12:34:56:01")/ <1>
+ IP(src="16.0.0.1",dst="48.0.0.1")/
+ UDP(dport=12,sport=1025)
+----
+<1> Specifying the source interface MAC replaces the default specified in the configuration YAML file.
+
+
+[IMPORTANT]
+=====================================
+TRex port will receive a packet only if the packet's destination MAC matches the HW Src MAC defined for that port in the `/etc/trex_cfg.yaml` configuration file. Alternatively, a port can be put into link:https://en.wikipedia.org/wiki/Promiscuous_mode[promiscuous mode], allowing the port to receive all packets on the line. The port can be configured to promiscuous mode by API or by the following command at the console: `portattr -a --prom`.
+=====================================
+
+To set ports to link:https://en.wikipedia.org/wiki/Promiscuous_mode[promiscuous mode] and show the port status:
+
+[source,bash]
+----
+trex>portattr -a --prom on #<1>
+trex>stats --ps
+Port Status
+
+ port | 0 | 1 |
+ ---------------------------------------------------------------
+driver | rte_ixgbe_pmd | rte_ixgbe_pmd |
+maximum | 10 Gb/s | 10 Gb/s |
+status | IDLE | IDLE |
+promiscuous | on | on | #<2>
+ -- | | |
+HW src mac | 90:e2:ba:36:33:c0 | 90:e2:ba:36:33:c1 |
+SW src mac | 00:00:00:01:00:00 | 00:00:00:01:00:00 |
+SW dst mac | 00:00:00:01:00:00 | 00:00:00:01:00:00 |
+ --- | | |
+PCI Address | 0000:03:00.0 | 0000:03:00.1 |
+NUMA Node | 0 | 0 |
+----
+<1> Configures all ports to promiscuous mode.
+<2> Indicates port promiscuous mode status.
+
+To change ports to promiscuous mode by Python API:
+
+.Python API to change ports to promiscuous mode
+[source,python]
+----
+ c = STLClient(verbose_level = LoggerApi.VERBOSE_REGULAR)
+
+ c.connect()
+
+ my_ports=[0,1]
+
+ # prepare our ports
+ c.reset(ports = my_ports)
+
+ # port info, mac-addr info, speed
+ print c.get_port_info(my_ports) <1>
+
+ c.set_port_attr(my_ports, promiscuous = True) <2>
+----
+<1> Get port info for all ports.
+<2> Change the port attribute to `promiscuous = True`.
+
+For more information see the link:cp_stl_docs/api/client_code.html[Python Client API].
+
+
+[NOTE]
+=====================================================================
+An interface is not set to promiscuous mode by default. Typically, after changing the port to promiscuous mode for a specific test, it is advisable to change it back to non-promiscuous mode.
+=====================================================================
+
+==== Tutorial: Python automation
+
+*Goal*:: Simple automation test using Python from a local or remote machine
+
+*Directories*::
+
+Python API examples: `automation/trex_control_plane/stl/examples`.
+
+Python API library: `automation/trex_control_plane/stl/trex_stl_lib`.
+
+The TRex console uses the Python API library to interact with the TRex server using the JSON-RPC2 protocol over ZMQ.
+
+image::images/trex_architecture_01.png[title="RPC Server Components",align="left",width={p_width}, link="images/trex_architecture_01.png"]
+
+// OBSOLETE: image::images/trex_2_stateless.png[title="RPC Server Components",align="left",width={p_width}, link="images/trex_2_stateless.png"]
+
+*File*:: link:{github_stl_examples_path}/stl_bi_dir_flows.py[stl_bi_dir_flows.py]
+
+
+[source,python]
+----
+import stl_path <1>
+from trex_stl_lib.api import * <2>
+
+import time
+import json
+
+# simple packet creation <3>
+def create_pkt (size, direction):
+
+ ip_range = {'src': {'start': "10.0.0.1", 'end': "10.0.0.254"},
+ 'dst': {'start': "8.0.0.1", 'end': "8.0.0.254"}}
+
+ if (direction == 0):
+ src = ip_range['src']
+ dst = ip_range['dst']
+ else:
+ src = ip_range['dst']
+ dst = ip_range['src']
+
+ vm = [
+ # src <4>
+ STLVmFlowVar(name="src",
+ min_value=src['start'],
+ max_value=src['end'],
+ size=4,op="inc"),
+ STLVmWrFlowVar(fv_name="src",pkt_offset= "IP.src"),
+
+ # dst
+ STLVmFlowVar(name="dst",
+ min_value=dst['start'],
+ max_value=dst['end'],
+ size=4,op="inc"),
+ STLVmWrFlowVar(fv_name="dst",pkt_offset= "IP.dst"),
+
+ # checksum
+ STLVmFixIpv4(offset = "IP")
+ ]
+
+
+ base = Ether()/IP()/UDP()
+ pad = max(0, len(base)) * 'x'
+
+ return STLPktBuilder(pkt = base/pad,
+ vm = vm)
+
+
+def simple_burst ():
+
+ # create client
+ c = STLClient()
+ # username/server can be changed those are the default
+ # username = common.get_current_user(),
+ # server = "localhost"
+ # STLClient(server = "my_server",username ="trex_client") for example
+ passed = True
+
+ try:
+ # turn this on for some information
+ #c.set_verbose("high")
+
+ # create two streams
+ s1 = STLStream(packet = create_pkt(200, 0),
+ mode = STLTXCont(pps = 100))
+
+ # second stream with a phase of 1ms (inter stream gap)
+ s2 = STLStream(packet = create_pkt(200, 1),
+ isg = 1000,
+ mode = STLTXCont(pps = 100))
+
+
+ # connect to server
+ c.connect() <5>
+
+ # prepare our ports (my machine has 0 <--> 1 with static route)
+ c.reset(ports = [0, 1]) # Acquire port 0,1 for $USER <6>
+
+ # add both streams to ports
+ c.add_streams(s1, ports = [0])
+ c.add_streams(s2, ports = [1])
+
+ # clear the stats before injecting
+ c.clear_stats()
+
+ # choose rate and start traffic for 10 seconds on 5 mpps
+ print "Running 5 Mpps on ports 0, 1 for 10 seconds..."
+ c.start(ports = [0, 1], mult = "5mpps", duration = 10) <7>
+
+ # block until done
+ c.wait_on_traffic(ports = [0, 1]) <8>
+
+ # read the stats after the test
+ stats = c.get_stats() <9>
+
+ print json.dumps(stats[0], indent = 4, separators=(',', ': '), sort_keys = True)
+ print json.dumps(stats[1], indent = 4, separators=(',', ': '), sort_keys = True)
+
+ lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
+ lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
+
+ print "\npackets lost from 0 --> 1: {0} pkts".format(lost_a)
+ print "packets lost from 1 --> 0: {0} pkts".format(lost_b)
+
+ if (lost_a == 0) and (lost_b == 0):
+ passed = True
+ else:
+ passed = False
+
+ except STLError as e:
+ passed = False
+ print e
+
+ finally:
+ c.disconnect() <10>
+
+ if passed:
+ print "\nTest has passed :-)\n"
+ else:
+ print "\nTest has failed :-(\n"
+
+
+# run the tests
+simple_burst()
+----
+<1> Imports the stl_path. The path here is specific to this example. When configuring, provide the path to your stl_trex library.
+<2> Imports TRex Stateless library. When configuring, provide the path to your TRex Stateless library.
+<3> Creates packet per direction using Scapy.
+<4> See the Field Engine section for information.
+<5> Connects to the local TRex. Username and server can be added.
+<6> Acquires the ports.
+<7> Loads the traffic profile and start generating traffic.
+<8> Waits for the traffic to be finished. There is a polling function so you can test do something while waiting.
+<9> Get port statistics.
+<10> Disconnects.
+
+See link:cp_stl_docs/index.html[TRex Stateless Python API] for details about using the Python APIs.
+
+
+==== Tutorial: HLT Python API
+
+HLT Python API is a layer on top of the native layer. It supports the standard Cisco traffic generator API. For more information, see Cisco/IXIA/Spirent documentation.
+TRex supports limited number of HLTAPI arguments and the recommendation is to use the native API due to the flexibility and simplicity.
+
+Supported HLT Python API classes:
+
+* Device Control
+** connect
+** cleanup_session
+** device_info
+** info
+* Interface
+** interface_config
+** interface_stats
+* Traffic
+** traffic_config - not all arguments are supported
+** traffic_control
+** traffic_stats
+
+// IGNORE: This line simply ends the bulletted section so that the next line will be formatted correctly.
+
+For details, see link:#_hlt_supported_arguments_a_id_altapi_support_a[Appendix]
+// confirm link above
+
+*File*:: link:{github_stl_examples_path}/hlt_udp_simple.py[hlt_udp_simple.py]
+
+
+[source,python]
+----
+
+import sys
+import argparse
+import stl_path
+from trex_stl_lib.api import * <1>
+from trex_stl_lib.trex_stl_hltapi import * <2>
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(usage="""
+ Connect to TRex and send burst of packets
+
+ examples
+
+ hlt_udp_simple.py -s 9000 -d 30
+
+ hlt_udp_simple.py -s 9000 -d 30 -rate_percent 10
+
+ hlt_udp_simple.py -s 300 -d 30 -rate_pps 5000000
+
+ hlt_udp_simple.py -s 800 -d 30 -rate_bps 500000000 --debug
+
+ then run the simulator on the output
+ ./stl-sim -f example.yaml -o a.pcap ==> a.pcap include the packet
+
+ """,
+ description="Example for TRex HLTAPI",
+ epilog=" based on hhaim's stl_run_udp_simple example")
+
+ parser.add_argument("--ip",
+ dest="ip",
+ help='Remote trex ip',
+ default="127.0.0.1",
+ type = str)
+
+ parser.add_argument("-s", "--frame-size",
+ dest="frame_size",
+ help='L2 frame size in bytes without FCS',
+ default=60,
+ type = int,)
+
+ parser.add_argument('-d','--duration',
+ dest='duration',
+ help='duration in second ',
+ default=10,
+ type = int,)
+
+ parser.add_argument('--rate-pps',
+ dest='rate_pps',
+ help='speed in pps',
+ default="100")
+
+ parser.add_argument('--src',
+ dest='src_mac',
+ help='src MAC',
+ default='00:50:56:b9:de:75')
+
+ parser.add_argument('--dst',
+ dest='dst_mac',
+ help='dst MAC',
+ default='00:50:56:b9:34:f3')
+
+ args = parser.parse_args()
+
+ hltapi = CTRexHltApi()
+ print 'Connecting to TRex'
+ res = hltapi.connect(device = args.ip, port_list = [0, 1], reset = True, break_locks = True)
+ check_res(res)
+ ports = res['port_handle']
+ if len(ports) < 2:
+ error('Should have at least 2 ports for this test')
+ print 'Connected, acquired ports: %s' % ports
+
+ print 'Creating traffic'
+
+ res = hltapi.traffic_config(mode = 'create', bidirectional = True,
+ port_handle = ports[0], port_handle2 = ports[1],
+ frame_size = args.frame_size,
+ mac_src = args.src_mac, mac_dst = args.dst_mac,
+ mac_src2 = args.dst_mac, mac_dst2 = args.src_mac,
+ l3_protocol = 'ipv4',
+ ip_src_addr = '10.0.0.1', ip_src_mode = 'increment', ip_src_count = 254,
+ ip_dst_addr = '8.0.0.1', ip_dst_mode = 'increment', ip_dst_count = 254,
+ l4_protocol = 'udp',
+ udp_dst_port = 12, udp_src_port = 1025,
+ stream_id = 1, # temporary workaround, add_stream does not return stream_id
+ rate_pps = args.rate_pps,
+ )
+ check_res(res)
+
+ print 'Starting traffic'
+ res = hltapi.traffic_control(action = 'run', port_handle = ports[:2])
+ check_res(res)
+ wait_with_progress(args.duration)
+
+ print 'Stopping traffic'
+ res = hltapi.traffic_control(action = 'stop', port_handle = ports[:2])
+ check_res(res)
+
+ res = hltapi.traffic_stats(mode = 'aggregate', port_handle = ports[:2])
+ check_res(res)
+ print_brief_stats(res)
+
+ res = hltapi.cleanup_session(port_handle = 'all')
+ check_res(res)
+
+ print 'Done'
+----
+<1> Imports the native TRex API.
+<2> Imports the HLT API.
+
+
+==== Tutorial: Simple IPv4/UDP packet - Simulator
+
+*Goal*:: Use the TRex Stateless simulator.
+
+Demonstrates the most basic use case using TRex simulator.
+
+The TRex package includes a simulator tool, `stl-sim`. The simulator operates as a Python script that calls an executable. The platform requirements for the simulator tool are the same as for TRex.
+
+The TRex simulator can:
+
+* Test your traffic profiles before running them on TRex.
+* Generate an output pcap file.
+* Simulate a number of threads.
+* Convert from one type of profile to another.
+* Convert any profile to JSON (API). For information, see: link:trex_rpc_server_spec.html#_add_stream[TRex stream specification]
+
+Example traffic profile:
+
+*File*:: link:{github_stl_path}/udp_1pkt_simple.py[stl/udp_1pkt_simple.py]
+
+[source,python]
+----
+from trex_stl_lib.api import *
+
+class STLS1(object):
+
+ def create_stream (self):
+
+ return STLStream(
+ packet =
+ STLPktBuilder(
+ pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/
+ UDP(dport=12,sport=1025)/(10*'x') <1>
+ ),
+ mode = STLTXCont()) <2>
+
+
+ def get_streams (self, direction = 0, **kwargs):
+ # create 1 stream
+ return [ self.create_stream() ]
+
+
+# dynamic load - used for TRex console or simulator
+def register(): <3>
+ return STLS1()
+----
+<1> Defines the packet - in this case, IP/UDP with 10 bytes of 'x'.
+<2> Mode is Continuous, with a rate of 1 PPS. (Default rate: 1 PPS)
+<3> Each traffic profile module requires a `register` function.
+
+The following runs the traffic profile through the TRex simulator, limiting the number of packets to 10, and storing the output in a pcap file.
+
+[source,bash]
+----
+$ ./stl-sim -f stl/udp_1pkt_simple.py -o b.pcap -l 10
+ executing command: 'bp-sim-64-debug --pcap --sl --cores 1 --limit 5000 -f /tmp/tmpq94Tfx -o b.pcap'
+
+ General info:
+ ------------
+
+ image type: debug
+ I/O output: b.pcap
+ packet limit: 10
+ core recording: merge all
+
+ Configuration info:
+ -------------------
+
+ ports: 2
+ cores: 1
+
+ Port Config:
+ ------------
+
+ stream count: 1
+ max PPS : 1.00 pps
+ max BPS L1 : 672.00 bps
+ max BPS L2 : 512.00 bps
+ line util. : 0.00 %
+
+
+ Starting simulation...
+
+
+ Simulation summary:
+ -------------------
+
+ simulated 10 packets
+ written 10 packets to 'b.pcap'
+----
+
+Contents of the output pcap file produced by the simulator in the previous step:
+
+image::images/stl_tut_1.png[title="TRex simulator output stored in pcap file",align="left",width={p_width}, link="images/stl_tut_1.png"]
+
+Adding `--json` displays the details of the JSON command for adding a stream:
+
+[source,bash]
+----
+$./stl-sim -f stl/udp_1pkt_simple.py --json
+[
+ {
+ "id": 1,
+ "jsonrpc": "2.0",
+ "method": "add_stream",
+ "params": {
+ "handler": 0,
+ "port_id": 0,
+ "stream": {
+ "action_count": 0,
+ "enabled": true,
+ "flags": 0,
+ "isg": 0.0,
+ "mode": {
+ "rate": {
+ "type": "pps",
+ "value": 1.0
+ },
+ "type": "continuous"
+ },
+ "next_stream_id": -1,
+ "packet": {
+ "binary": "AAAAAQAAAAAAAgAACABFAAAmAA",
+ "meta": ""
+ },
+ "rx_stats": {
+ "enabled": false
+ },
+ "self_start": true,
+ "vm": {
+ "instructions": [],
+ "split_by_var": ""
+ }
+ },
+ "stream_id": 1
+ }
+ },
+ {
+ "id": 1,
+ "jsonrpc": "2.0",
+ "method": "start_traffic",
+ "params": {
+ "duration": -1,
+ "force": true,
+ "handler": 0,
+ "mul": {
+ "op": "abs",
+ "type": "raw",
+ "value": 1.0
+ },
+ "port_id": 0
+ }
+ }
+]
+----
+
+For more information about stream definition, see the link:trex_rpc_server_spec.html#_add_stream[RPC specification].
+
+To convert the profile to YAML format:
+[source,bash]
+----
+$./stl-sim -f stl/udp_1pkt_simple.py --yaml
+- stream:
+ action_count: 0
+ enabled: true
+ flags: 0
+ isg: 0.0
+ mode:
+ pps: 1.0
+ type: continuous
+ packet:
+ binary: AAAAAQAAAAAAAgAACABFAAAmAAEAAEARO
+ meta: ''
+ rx_stats:
+ enabled: false
+ self_start: true
+ vm:
+ instructions: []
+ split_by_var: ''
+----
+
+To display packet details, use the `--pkt` option (using Scapy).
+
+[source,bash]
+----
+$./stl-sim -f stl/udp_1pkt_simple.py --pkt
+ =======================
+ Stream 0
+ =======================
+###[ Ethernet ]###
+ dst = 00:00:00:01:00:00
+ src = 00:00:00:02:00:00
+ type = IPv4
+###[ IP ]###
+ version = 4L
+ ihl = 5L
+ tos = 0x0
+ len = 38
+ id = 1
+ flags =
+ frag = 0L
+ ttl = 64
+ proto = udp
+ chksum = 0x3ac5
+ src = 16.0.0.1
+ dst = 48.0.0.1
+ \options \
+###[ UDP ]###
+ sport = blackjack
+ dport = 12
+ len = 18
+ chksum = 0x6161
+###[ Raw ]###
+ load = 'xxxxxxxxxx'
+0000 00 00 00 01 00 00 00 00 00 02 00 00 08 00 45 00 ..............E.
+0010 00 26 00 01 00 00 40 11 3A C5 10 00 00 01 30 00 .&....@.:.....0.
+0020 00 01 04 01 00 0C 00 12 61 61 78 78 78 78 78 78 ........aaxxxxxx
+0030 78 78 78 78 xxxx
+----
+
+To convert any profile type to native again, use the `--native` option:
+
+.Input YAML format
+[source,python]
+----
+$more stl/yaml/imix_1pkt.yaml
+- name: udp_64B
+ stream:
+ self_start: True
+ packet:
+ pcap: udp_64B_no_crc.pcap # pcap should not include CRC
+ mode:
+ type: continuous
+ pps: 100
+----
+
+To convert to native:
+
+[source,bash]
+----
+$./stl-sim -f stl/yaml/imix_1pkt.yaml --native
+----
+
+
+.Output Native
+[source,python]
+----
+# !!! Auto-generated code !!!
+from trex_stl_lib.api import *
+
+class STLS1(object):
+ def get_streams(self):
+ streams = []
+
+ packet = (Ether(src='00:de:01:0a:01:00', dst='00:50:56:80:0d:28', type=2048) /
+ IP(src='101.0.0.1', proto=17, dst='102.0.0.1', chksum=28605, len=46, flags=2L, ihl=5L, id=0) /
+ UDP(dport=2001, sport=2001, len=26, chksum=1176) /
+ Raw(load='\xde\xad\xbe\xef\x00\x01\x06\x07\x08\x09\x0a\x0b\x00\x9b\xe7\xdb\x82M'))
+ vm = STLScVmRaw([], split_by_field = '')
+ stream = STLStream(packet = CScapyTRexPktBuilder(pkt = packet, vm = vm),
+ name = 'udp_64B',
+ mac_src_override_by_pkt = 0,
+ mac_dst_override_mode = 0,
+ mode = STLTXCont(pps = 100))
+ streams.append(stream)
+
+ return streams
+
+def register():
+ return STLS1()
+----
+
+*Discussion*::
+
+The following are the main traffic profile formats. Native is the preferred format. There is a separation between how the traffic is defined and how to control/activate it. The API/Console/GUI can load a traffic profile and start/stop/get a statistic. Due to this separation it is possible to share traffic profiles.
+
+.Traffic profile formats
+[cols="1^,1^,10<", options="header",width="80%"]
+|=================
+| Profile Type | Format | Description
+| Native | Python | Most flexibile. Any format can be converted to native using the `stl-sim` command with the `--native` option.
+| HLT | Python | Uses HLT arguments.
+| YAML | YAML | The common denominator traffic profile. Information is shared between console, GUI, and simulator in YAML format. This format is difficult to use for defining packets; primarily for machine use. YAML can be converted to native using the `stl-sim` command with the `--native` option.
+|=================
+
+
+=== Traffic profile Tutorials
+
+==== Tutorial: Simple Interleaving streams
+
+*Goal*:: Demonstrate interleaving of multiple streams.
+
+The following example demonstrates 3 streams with different rates (10, 20, 40 PPS) and different start times, based on an inter-stream gap (ISG) of 0, 25 msec, or 50 msec.
+
+*File*:: link:{github_stl_path}/simple_3pkt.py[stl/simple_3pkt.py]
+
+// inserted this comment to fix rendering problem - otherwise the next several lines are not rendered
+// there's still a problem with the rendering. the image is not displayed.
+
+
+.Interleaving multiple streams
+[source,python]
+----
+ def create_stream (self):
+
+ # create a base packet and pad it to size
+ size = self.fsize - 4 # no FCS
+ base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) <1>
+ base_pkt1 = Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+ base_pkt2 = Ether()/IP(src="16.0.0.3",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+ pad = max(0, size - len(base_pkt)) * 'x'
+
+
+ return STLProfile( [ STLStream( isg = 0.0,
+ packet = STLPktBuilder(pkt = base_pkt/pad),
+ mode = STLTXCont( pps = 10), <2>
+ ),
+
+ STLStream( isg = 25000.0, #defined in usec, 25 msec
+ packet = STLPktBuilder(pkt = base_pkt1/pad),
+ mode = STLTXCont( pps = 20), <3>
+ ),
+
+ STLStream( isg = 50000.0,#defined in usec, 50 msec
+ packet = STLPktBuilder(pkt = base_pkt2/pad),
+ mode = STLTXCont( pps = 40) <4>
+
+ )
+ ]).get_streams()
+----
+<1> Defines template packets using Scapy.
+<2> Defines streams with rate of 10 PPS.
+<3> Defines streams with rate of 20 PPS.
+<4> Defines streams with rate of 40 PPS.
+
+*Output*::
+
+The folowing figure presents the output.
+
+image::images/stl_interleaving_01.png[title="Interleaving of streams",align="left",width={p_width}, link="images/stl_interleaving_01.png"]
+
+*Discussion*::
+* Stream #1
+** Schedules a packet each 100 msec
+* Stream #2
+** Schedules a packet each 50 msec
+** Starts 25 msec after stream #1
+* Stream #3
+** Schedules a packet each 25 msec
+** Starts 50 msec after stream #1
+
+You can run the traffic profile in the TRex simulator and view the details in the pcap file containing the simulation output.
+
+[source,bash]
+----
+$./stl-sim -f stl/simple_3pkt.py -o b.pcap -l 200
+----
+
+To run the traffic profile from console in TRex, use the following command.
+
+[source,bash]
+----
+trex>start -f stl/simple_3pkt.py -m 10mbps -a
+----
+
+==== Tutorial: Multi burst streams - action next stream
+
+*Goal*:: Create a profile with a stream that trigger another stream
+
+The following example demonstrates:
+
+1. More than one stream
+2. Burst of 10 packets
+3. One stream activating another stream (see `self_start=False` in the traffic profile)
+
+*File*:: link:{github_stl_path}/burst_3pkt_60pkt.py[stl/burst_3pkt_60pkt.py]
+
+
+[source,python]
+----
+ def create_stream (self):
+
+ # create a base packet and pad it to size
+ size = self.fsize - 4 # no FCS
+ base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+ base_pkt1 = Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+ base_pkt2 = Ether()/IP(src="16.0.0.3",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+ pad = max(0, size - len(base_pkt)) * 'x'
+
+
+ return STLProfile( [ STLStream( isg = 10.0, # star in delay
+ name ='S0',
+ packet = STLPktBuilder(pkt = base_pkt/pad),
+ mode = STLTXSingleBurst( pps = 10, total_pkts = 10), <1>
+ next = 'S1'), # point to next stream
+
+ STLStream( self_start = False, # stream is disabled enable trow S0 <2>
+ name ='S1',
+ packet = STLPktBuilder(pkt = base_pkt1/pad),
+ mode = STLTXSingleBurst( pps = 10, total_pkts = 20),
+ next = 'S2' ),
+
+ STLStream( self_start = False, # stream is disabled enable trow S0 <3>
+ name ='S2',
+ packet = STLPktBuilder(pkt = base_pkt2/pad),
+ mode = STLTXSingleBurst( pps = 10, total_pkts = 30 )
+ )
+ ]).get_streams()
+
+----
+<1> Stream S0 is configured to `self_start=True`, starts after 10 sec.
+<2> S1 is configured to `self_start=False`, activated by stream S0.
+<3> S2 is activated by S1.
+
+To run the simulation, use this command.
+
+[source,bash]
+----
+$ ./stl-sim -f stl/stl/burst_3pkt_60pkt.py -o b.pcap
+----
+
+The generated pcap file has 60 packets. The first 10 packets have src_ip=16.0.0.1. The next 20 packets has src_ip=16.0.0.2. The next 30 packets has src_ip=16.0.0.3.
+
+This run the profile from console use this command.
+
+[source,bash]
+----
+TRex>start -f stl/stl/burst_3pkt_60pkt.py --port 0
+----
+
+==== Tutorial: Multi-burst mode
+
+*Goal* : Use Multi-burst transmit mode
+
+*File*:: link:{github_stl_path}/multi_burst_2st_1000pkt.py[stl/multi_burst_2st_1000pkt.py]
+
+[source,python]
+----
+
+ def create_stream (self):
+
+ # create a base packet and pad it to size
+ size = self.fsize - 4 # no FCS
+ base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+ base_pkt1 = Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+ pad = max(0, size - len(base_pkt)) * 'x'
+
+
+ return STLProfile( [ STLStream( isg = 10.0, # start in delay <1>
+ name ='S0',
+ packet = STLPktBuilder(pkt = base_pkt/pad),
+ mode = STLTXSingleBurst( pps = 10, total_pkts = 10),
+ next = 'S1'), # point to next stream
+
+ STLStream( self_start = False, # stream is disabled. Enabled by S0 <2>
+ name ='S1',
+ packet = STLPktBuilder(pkt = base_pkt1/pad),
+ mode = STLTXMultiBurst( pps = 1000,
+ pkts_per_burst = 4,
+ ibg = 1000000.0,
+ count = 5)
+ )
+
+ ]).get_streams()
+
+----
+<1> Stream S0 waits 10 usec (inter-stream gap, ISG) and then sends a burst of 10 packets at 10 PPS.
+<2> Multi-burst of 5 bursts of 4 packets with an inter-burst gap of 1 second.
+
+
+The following illustration does not fully match the Python example cited above. It has been simplified, such as using a 0.5 second ISG, for illustration purposes.
+
+image::images/stl_multiple_streams_01.png[title="Example of multiple streams",align="left",width={p_width_lge}, link="images/stl_multiple_streams_01.png"]
+
+
+
+==== Tutorial: Loops of streams
+
+*Goal* : Demonstrate a limited loop of streams
+
+*File*:: link:{github_stl_path}/burst_3st_loop_x_times.py[stl/burst_3st_loop_x_times.py]
+
+[source,python]
+----
+ def create_stream (self):
+
+ # create a base packet and pad it to size
+ size = self.fsize - 4 # no FCS
+ base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+ base_pkt1 = Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+ base_pkt2 = Ether()/IP(src="16.0.0.3",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+ pad = max(0, size - len(base_pkt)) * 'x'
+
+
+ return STLProfile( [ STLStream( isg = 10.0, # start in delay
+ name ='S0',
+ packet = STLPktBuilder(pkt = base_pkt/pad),
+ mode = STLTXSingleBurst( pps = 10, total_pkts = 1),
+ next = 'S1'), # point to next stream
+
+ STLStream( self_start = False, # stream is disabled. Enabled by S0
+ name ='S1',
+ packet = STLPktBuilder(pkt = base_pkt1/pad),
+ mode = STLTXSingleBurst( pps = 10, total_pkts = 2),
+ next = 'S2' ),
+
+ STLStream( self_start = False, # stream is disabled. Enabled by S1
+ name ='S2',
+ packet = STLPktBuilder(pkt = base_pkt2/pad),
+ mode = STLTXSingleBurst( pps = 10, total_pkts = 3 ),
+ action_count = 2, # loop 2 times <1>
+ next = 'S0' # loop back to S0
+ )
+ ]).get_streams()
+
+----
+<1> go back to S0 but limit it to 2 loops
+
+
+==== Tutorial: IMIX with UDP packets, bi-directional
+
+*Goal* : Demonstrate how to create an IMIX traffic profile.
+
+This profile defines 3 streams, with packets of different sizes. The rate is different for each stream/size. See the link:https://en.wikipedia.org/wiki/Internet_Mix[Wikipedia article on Internet Mix].
+
+*File*:: link:{github_stl_path}/imix.py[stl/imix.py]
+
+[source,python]
+----
+ def __init__ (self):
+ # default IP range
+ self.ip_range = {'src': {'start': "10.0.0.1", 'end': "10.0.0.254"},
+ 'dst': {'start': "8.0.0.1", 'end': "8.0.0.254"}}
+
+ # default IMIX properties
+ self.imix_table = [ {'size': 60, 'pps': 28, 'isg':0 },
+ {'size': 590, 'pps': 16, 'isg':0.1 },
+ {'size': 1514, 'pps': 4, 'isg':0.2 } ]
+
+
+ def create_stream (self, size, pps, isg, vm ):
+ # create a base packet and pad it to size
+ base_pkt = Ether()/IP()/UDP()
+ pad = max(0, size - len(base_pkt)) * 'x'
+
+ pkt = STLPktBuilder(pkt = base_pkt/pad,
+ vm = vm)
+
+ return STLStream(isg = isg,
+ packet = pkt,
+ mode = STLTXCont(pps = pps))
+
+
+ def get_streams (self, direction = 0, **kwargs): <1>
+
+ if direction == 0: <2>
+ src = self.ip_range['src']
+ dst = self.ip_range['dst']
+ else:
+ src = self.ip_range['dst']
+ dst = self.ip_range['src']
+
+ # construct the base packet for the profile
+
+ vm =[ <3>
+ # src
+ STLVmFlowVar(name="src",
+ min_value=src['start'],
+ max_value=src['end'],
+ size=4,op="inc"),
+ STLVmWrFlowVar(fv_name="src",pkt_offset= "IP.src"),
+
+ # dst
+ STLVmFlowVar(name="dst",
+ min_value=dst['start'],
+ max_value=dst['end'],
+ size=4,
+ op="inc"),
+ STLVmWrFlowVar(fv_name="dst",pkt_offset= "IP.dst"),
+
+ # checksum
+ STLVmFixIpv4(offset = "IP")
+
+ ]
+
+ # create imix streams
+ return [self.create_stream(x['size'], x['pps'],x['isg'] , vm) for x in self.imix_table]
+----
+<1> Constructs a diffrent stream for each direction (replaces src and dest).
+<2> Even port id has direction==0 and odd has direction==1.
+// direction==1 not shown explicitly in the code?
+<3> Field Engine program to change fields within the packets.
+// we can link "Field Engine" to an appropriate location for for more info.
+
+==== Tutorial: Field Engine, Syn attack
+
+The following example demonstrates changing packet fields. The Field Engine (FE) has a limited number of instructions/operation, which support most use cases.
+
+*The FE can*::
+* Allocate stream variables in a stream context
+* Write a stream variable to a packet offset
+* Change packet size
+* and more...
+* There is a plan to add LuaJIT to be more flexible at the cost of performance.
+
+*Examples:*::
+* Change ipv4.tos value (1 to 10)
+* Change packet size to a random value in the range 64 to 9K
+* Create a range of flows (change src_ip, dest_ip, src_port, dest_port)
+* Update the IPv4 checksum
+
+For more information, see link:trex_rpc_server_spec.html#_object_type_em_vm_em_a_id_vm_obj_a[here]
+// add link to Python API: http://trex-tgn.cisco.com/trex/doc/cp_stl_docs/api/field_engine.html
+
+The following example demonstrates creating a SYN attack from many src addresses to one server.
+
+*File*:: link:{github_stl_path}/syn_attack.py[stl/syn_attack.py]
+
+[source,python]
+----
+ def create_stream (self):
+
+ # TCP SYN
+ base_pkt = Ether()/IP(dst="48.0.0.1")/TCP(dport=80,flags="S") <1>
+
+
+ # vm
+ vm = STLScVmRaw( [ STLVmFlowVar(name="ip_src",
+ min_value="16.0.0.0",
+ max_value="18.0.0.254",
+ size=4, op="random"), <2>
+
+ STLVmFlowVar(name="src_port",
+ min_value=1025,
+ max_value=65000,
+ size=2, op="random"), <3>
+
+ STLVmWrFlowVar(fv_name="ip_src", pkt_offset= "IP.src" ), <4>
+
+ STLVmFixIpv4(offset = "IP"), # fix checksum <5>
+
+ STLVmWrFlowVar(fv_name="src_port", <6>
+ pkt_offset= "TCP.sport") # U
+
+ ]
+ )
+
+ pkt = STLPktBuilder(pkt = base_pkt,
+ vm = vm)
+
+ return STLStream(packet = pkt,
+ random_seed = 0x1234,# can be removed. will give the same random value any run
+ mode = STLTXCont())
+----
+<1> Creates SYN packet using Scapy .
+<2> Defines a stream variable `name=ip_src`, size 4 bytes, for IPv4.
+<3> Defines a stream variable `name=src_port`, size 2 bytes, for port.
+<4> Writes `ip_src` stream var into `IP.src` packet offset. Scapy calculates the offset. Can specify `IP:1.src` for a second IP header in the packet.
+<5> Fixes IPv4 checksum. Provides the header name `IP`. Can specify `IP:1` for a second IP.
+<6> Writes `src_port` stream var into `TCP.sport` packet offset. TCP checksum is not updated here.
+
+WARNING: Original Scapy cannot calculate offset for a header/field by name. This offset capability will not work for all cases. In some complex cases, Scapy may rebuild the header. In such cases, specify the offset as a number.
+
+Output pcap file:
+
+.Output - pcap file
+[format="csv",cols="1^,2<,2<", options="header",width="40%"]
+|=================
+pkt,Client IPv4,Client Port
+ 1 , 17.152.71.218 , 5814
+ 2 , 17.7.6.30 , 26810
+ 3 , 17.3.32.200 , 1810
+ 4 , 17.135.236.168 , 55810
+ 5 , 17.46.240.12 , 1078
+ 6 , 16.133.91.247 , 2323
+|=================
+
+
+==== Tutorial: Field Engine, Tuple Generator
+
+The following example creates multiple flows from the same packet template. The Tuple Generator instructions are used to create two stream variables for IP and port. See link:trex_rpc_server_spec.html#_object_type_em_vm_em_a_id_vm_obj_a[here]
+// clarify link
+
+*File*:: link:{github_stl_path}/udp_1pkt_tuple_gen.py[stl/udp_1pkt_tuple_gen.py]
+
+[source,python]
+----
+ base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+
+ pad = max(0, size - len(base_pkt)) * 'x'
+
+ vm = STLScVmRaw( [ STLVmTupleGen ( ip_min="16.0.0.1", <1>
+ ip_max="16.0.0.2",
+ port_min=1025,
+ port_max=65535,
+ name="tuple"), # define tuple gen
+
+ STLVmWrFlowVar (fv_name="tuple.ip", pkt_offset= "IP.src" ), <2>
+ STLVmFixIpv4(offset = "IP"),
+ STLVmWrFlowVar (fv_name="tuple.port", pkt_offset= "UDP.sport" ) <3>
+ ]
+ )
+
+ pkt = STLPktBuilder(pkt = base_pkt/pad,
+ vm = vm)
+----
+<1> Defines a struct with two dependent variables: tuple.ip, tuple.port
+<2> Writes the tuple.ip variable to `IPv4.src` field offset.
+<3> Writes the tuple.port variable to `UDP.sport` field offset. Set `UDP.checksum` to 0.
+// Hanoch: add how to set UDP.checksum to 0
+
+
+.Output - pcap file
+[format="csv",cols="1^,2^,1^", options="header",width="40%"]
+|=================
+pkt,Client IPv4,Client Port
+ 1 , 16.0.0.1 , 1025
+ 2 , 16.0.0.2 , 1025
+ 3 , 16.0.0.1 , 1026
+ 4 , 16.0.0.2 , 1026
+ 5 , 16.0.0.1 , 1027
+ 6 , 16.0.0.2, 1027
+|=================
+
+* Number of clients: 2: 16.0.0.1 and 16.0.0.2
+* Number of flows is limited to 129020: (2 * (65535-1025))
+* The stream variable size should match the size of the FlowVarWr instruction.
+
+==== Tutorial: Field Engine, write to a bit-field packet
+
+The following example writes a stream variable to a bit field packet variable. In this example, an MPLS label field is changed.
+
+.MPLS header
+[cols="32", halign="center",width="50%"]
+|====
+20+<|Label 3+<|TC 1+<|S 8+<|TTL|
+0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|7|8|9|0|1|
+|====
+
+*File*:: link:{github_stl_path}/udp_1pkt_mpls_vm.py[stl/udp_1pkt_mpls_vm.py]
+
+[source,python]
+----
+
+ def create_stream (self):
+ # 2 MPLS label the internal with s=1 (last one)
+ pkt = Ether()/
+ MPLS(label=17,cos=1,s=0,ttl=255)/
+ MPLS(label=0,cos=1,s=1,ttl=12)/
+ IP(src="16.0.0.1",dst="48.0.0.1")/
+ UDP(dport=12,sport=1025)/('x'*20)
+
+ vm = STLScVmRaw( [ STLVmFlowVar(name="mlabel", <1>
+ min_value=1,
+ max_value=2000,
+ size=2, op="inc"), # 2 bytes var <2>
+ STLVmWrMaskFlowVar(fv_name="mlabel",
+ pkt_offset= "MPLS:1.label", <3>
+ pkt_cast_size=4,
+ mask=0xFFFFF000,shift=12) # write to 20bit MSB
+ ]
+ )
+
+ # burst of 100 packets
+ return STLStream(packet = STLPktBuilder(pkt = pkt ,vm = vm),
+ mode = STLTXSingleBurst( pps = 1, total_pkts = 100) )
+
+----
+<1> Defines a variable size of 2 bytes.
+<2> Writes the stream variable label with a shift of 12 bits, with a 20-bit MSB mask. Cast the stream variables of 2 bytes to 4 bytes.
+<3> Change the second MPLS header.
+
+
+==== Tutorial: Field Engine, Random packet size
+
+The following example demonstrates varies the packet size randomly, as follows:
+
+1. Defines the template packet with maximum size.
+2. Trims the packet to the size you want.
+3. Updates the packet fields according to the new size.
+
+*File*:: link:{github_stl_path}/udp_rand_len_9k.py[stl/udp_rand_len_9k.py]
+
+[source,python]
+----
+
+ def create_stream (self):
+ # pkt
+ p_l2 = Ether()
+ p_l3 = IP(src="16.0.0.1",dst="48.0.0.1")
+ p_l4 = UDP(dport=12,sport=1025)
+ pyld_size = max(0, self.max_pkt_size_l3 - len(p_l3/p_l4))
+ base_pkt = p_l2/p_l3/p_l4/('\x55'*(pyld_size))
+
+ l3_len_fix =-(len(p_l2))
+ l4_len_fix =-(len(p_l2/p_l3))
+
+
+ # vm
+ vm = STLScVmRaw( [ STLVmFlowVar(name="fv_rand", <1>
+ min_value=64,
+ max_value=len(base_pkt),
+ size=2,
+ op="random"),
+
+ STLVmTrimPktSize("fv_rand"), # total packet size <2>
+
+ STLVmWrFlowVar(fv_name="fv_rand", <3>
+ pkt_offset= "IP.len",
+ add_val=l3_len_fix), # fix ip len
+
+ STLVmFixIpv4(offset = "IP"),
+
+ STLVmWrFlowVar(fv_name="fv_rand", <4>
+ pkt_offset= "UDP.len",
+ add_val=l4_len_fix) # fix udp len
+ ]
+ )
+----
+<1> Defines a random stream variable with the maximum size of the packet.
+<2> Trims the packet size to the `fv_rand` value.
+<3> Fixes ip.len to reflect the packet size.
+<4> Fixes udp.len to reflect the packet size.
+
+
+==== Tutorial: Field Engine, Significantly improve performance
+
+anchor:trex_cache_mbuf[]
+
+The following example demonstrates a way to significantly improve Field Engine performance in case it is needed.
+
+Field Engine has a cost of CPU instructions and CPU memory bandwidth. There is a way to significantly improve performance by caching the packets and run the Field Engine offline(before sending the packets).
+The limitation is that you can have only a limited number of packets that can be cached (order or 10K depends how much memory you have).
+For example a program that change the src_ip to a random value can't be utilized this technique and still have random src_ip.
+Usually this is done with small packets (64bytes) where performance is an issue. This method can improve long packets senario with a complex Field Engine program.
+
+*File*:: link:{github_stl_path}/udp_1pkt_src_ip_split.py[stl/udp_1pkt_src_ip_split.py]
+
+[source,python]
+----
+
+ def create_stream (self):
+ # create a base packet and pad it to size
+ size = self.fsize - 4; # no FCS
+
+ base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+
+ pad = max(0, size - len(base_pkt)) * 'x'
+
+ vm = STLScVmRaw( [ STLVmFlowVar ( "ip_src",
+ min_value="10.0.0.1",
+ max_value="10.0.0.255",
+ size=4, step=1,op="inc"),
+
+ STLVmWrFlowVar (fv_name="ip_src",
+ pkt_offset= "IP.src" ),
+
+ STLVmFixIpv4(offset = "IP")
+ ],
+ split_by_field = "ip_src",
+ cache_size =255 # the cache size <1>
+ );
+
+ pkt = STLPktBuilder(pkt = base_pkt/pad,
+ vm = vm)
+
+ stream = STLStream(packet = pkt,
+ mode = STLTXCont())
+ return stream
+
+----
+<1> Cache 255 packets. The range is the same as `ip_src` stream variable
+
+This FE program will run *x2-5 faster* compared to native (without cache).
+In this specific example the output will be *exactly* the same.
+
+Again the limitations of this method are:
+
+1. The total number of cache packets for all the streams all the ports in limited by the memory pool (range of ~10-40K)
+2. There could be cases that the cache options won't be exactly the same as the normal program, for example, in case of a program that step in prime numbers or with a random variable
+
+
+==== Tutorial: New Scapy header
+
+The following example uses a header that is not supported by Scapy by default. The example demonstrates VXLAN support.
+
+*File*:: link:{github_stl_path}/udp_1pkt_vxlan.py[stl/udp_1pkt_vxlan.py]
+
+[source,python]
+----
+
+# Adding header that does not exists yet in Scapy
+# This was taken from pull request of Scapy
+#
+
+
+# RFC 7348 - Virtual eXtensible Local Area Network (VXLAN): <1>
+# A Framework for Overlaying Virtualized Layer 2 Networks over Layer 3 Networks
+# http://tools.ietf.org/html/rfc7348
+_VXLAN_FLAGS = ['R' for i in range(0, 24)] + ['R', 'R', 'R', 'I', 'R', 'R', 'R', 'R', 'R']
+
+class VXLAN(Packet):
+ name = "VXLAN"
+ fields_desc = [FlagsField("flags", 0x08000000, 32, _VXLAN_FLAGS),
+ ThreeBytesField("vni", 0),
+ XByteField("reserved", 0x00)]
+
+ def mysummary(self):
+ return self.sprintf("VXLAN (vni=%VXLAN.vni%)")
+
+bind_layers(UDP, VXLAN, dport=4789)
+bind_layers(VXLAN, Ether)
+
+
+class STLS1(object):
+
+ def __init__ (self):
+ pass
+
+ def create_stream (self):
+ pkt = Ether()/IP()/UDP(sport=1337,dport=4789)/VXLAN(vni=42)/Ether()/IP()/('x'*20) <2>
+ #pkt.show2()
+ #hexdump(pkt)
+
+ # burst of 17 packets
+ return STLStream(packet = STLPktBuilder(pkt = pkt ,vm = []),
+ mode = STLTXSingleBurst( pps = 1, total_pkts = 17) )
+
+
+----
+<1> Downloads and adds a Scapy header from the specified location. Alternatively, write a Scapy header.
+<2> Apply the header.
+
+For more information how to define headers see link:http://www.secdev.org/projects/scapy/doc/build_dissect.html[Adding new protocols] in the Scapy documentation.
+
+
+==== Tutorial: Field Engine, Multiple Clients
+
+The following example generates traffic from many clients with different IP/MAC addresses to one server.
+
+// Please leave this comment - helping rendition of image below.
+
+image::images/stl_multiple_clients_01b.png[title="Multiple clients to single server",align="left",width="80%", link="images/stl_multiple_clients_01b.png"]
+
+// OBSOLETEimage::images/stl_tut_12.png[title="client->server",align="left",width={p_width}, link="images/stl_tut_12.png"]
+
+1. Send a gratuitous ARP from B->D with server IP/MAC (58.55.1.1).
+2. DUT learns the ARP of server IP/MAC (58.55.1.1).
+3. Send traffic from A->C with many client IP/MAC addresses.
+
+Example:
+
+Base source IPv4 : 55.55.1.1
+Destination IPv4: 58.55.1.1
+
+Increment src ipt portion starting at 55.55.1.1 for 'n' number of clients (55.55.1.1, 55.55.1.2)
+Src MAC: start with 0000.dddd.0001, increment mac in steps of 1
+Dst MAC: Fixed - 58.55.1.1
+
+The following sends a link:https://wiki.wireshark.org/Gratuitous_ARP[gratuitous ARP] from the TRex server port for this server (58.0.0.1).
+
+[source,python]
+----
+ def create_stream (self):
+ # create a base packet and pad it to size
+ base_pkt = Ether(src="00:00:dd:dd:01:01",
+ dst="ff:ff:ff:ff:ff:ff")/
+ ARP(psrc="58.55.1.1",
+ hwsrc="00:00:dd:dd:01:01",
+ hwdst="00:00:dd:dd:01:01",
+ pdst="58.55.1.1")
+----
+
+Then traffic can be sent from client side: A->C
+
+*File*:: link:{github_stl_path}/udp_1pkt_range_clients_split.py[stl/udp_1pkt_range_clients_split.py]
+
+[source,python]
+----
+class STLS1(object):
+
+ def __init__ (self):
+ self.num_clients =30000 # max is 16bit
+ self.fsize =64
+
+ def create_stream (self):
+
+ # create a base packet and pad it to size
+ size = self.fsize - 4 # no FCS
+ base_pkt = Ether(src="00:00:dd:dd:00:01")/
+ IP(src="55.55.1.1",dst="58.55.1.1")/UDP(dport=12,sport=1025)
+ pad = max(0, size - len(base_pkt)) * 'x'
+
+ vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src",
+ min_value=1,
+ max_value=self.num_clients,
+ size=2, op="inc"), # 1 byte varible, range 1-10
+
+ STLVmWrFlowVar(fv_name="mac_src", pkt_offset= 10), <1>
+ STLVmWrFlowVar(fv_name="mac_src" ,
+ pkt_offset="IP.src",
+ offset_fixup=2), <2>
+ STLVmFixIpv4(offset = "IP")
+ ]
+ ,split_by_field = "mac_src" # split
+ )
+
+ return STLStream(packet = STLPktBuilder(pkt = base_pkt/pad,vm = vm),
+ mode = STLTXCont( pps=10 ))
+----
+<1> Writes the stream variable `mac_src` with an offset of 10 (last 2 bytes of `src_mac` field). The offset is specified explicitly as 10 bytes from the beginning of the packet.
+<2> Writes the stream variable `mac_src` with an offset determined by the offset of `IP.src` plus the `offset_fixup` of 2.
+
+
+==== Tutorial: Field Engine, many clients with ARP
+
+In the following example, there are two Switchs SW1 and SW2.
+TRex port 0 is connected to SW1 and TRex port 1 is connected to SW2.
+There are 253 hosts connected to SW1 and SW2 with two network ports.
+
+.Client side the network of the hosts
+[cols="3<,3<", options="header",width="50%"]
+|=================
+| Name | Description
+| TRex port 0 MAC | 00:00:01:00:00:01
+| TRex port 0 IPv4 | 16.0.0.1
+| IPv4 host client side range | 16.0.0.2-16.0.0.254
+| MAC host client side range | 00:00:01:00:00:02-00:00:01:00:00:FE
+|=================
+
+
+.Server side the network of the hosts
+[cols="3<,3<", options="header",width="50%"]
+|=================
+| Name | Description
+| TRex port 1 MAC | 00:00:02:00:00:01
+| TRex port 1 IPv4 | 48.0.0.1
+| IPv4 host server side range | 48.0.0.2-48.0.0.254
+| MAC host server side range | 00:00:02:00:00:02-00:00:02:00:00:FE
+|=================
+
+image::images/stl_arp.png[title="arp/nd",align="left",width={p_width}, link="images/stl_arp.png"]
+
+In the following example, there are two Switchs SW1 and SW2.
+TRex port 0 is connected to SW1 and TRex port 1 is connected to SW2
+In this example, because there are many hosts connected to the same network using SW1 and not as a next hope, we would like to teach SW1 the MAC addresses of the hosts and not to send the traffic directly to the hosts MAC (as it is unknown)
+For that we would send an ARP to all the hosts (16.0.0.2-16.0.0.254) from TRex port 0 and gratuitous ARP from server side (48.0.0.1) TRex port 1 as the first stage of the test
+
+So the step would be like that:
+
+1. Send a gratuitous ARP from TRex port 1 with server IP/MAC (48.0.0.1) after this stage SW2 will know that 48.0.0.1 is located after this port of SW2.
+2. Send ARP request for all hosts from port 0 with a range of 16.0.0.2-16.0.0.254 after this stage all switch ports will learn the PORT/MAC locations. Without this stage the first packets from TRex port 0 will be flooded to all Switch ports.
+3. send traffic from TRex0->clients, port 1->servers
+
+
+.ARP traffic profile
+[source,python]
+----
+
+ base_pkt = Ether(dst="ff:ff:ff:ff:ff:ff")/
+ ARP(psrc="16.0.0.1",hwsrc="00:00:01:00:00:01", pdst="16.0.0.2") <1>
+
+ vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src", min_value=2, max_value=254, size=2, op="inc"), <2>
+ STLVmWrFlowVar(fv_name="mac_src" ,pkt_offset="ARP.pdst",offset_fixup=2),
+ ]
+ ,split_by_field = "mac_src" # split
+ )
+
+
+----
+<1> ARP packet with TRex port 0 MAC and IP and pdst as variable.
+<2> Write it to `ARP.pdst`.
+
+
+.Gratuitous ARP traffic profile
+[source,python]
+----
+
+ base_pkt = Ether(src="00:00:02:00:00:01",dst="ff:ff:ff:ff:ff:ff")/
+ ARP(psrc="48.0.0.1",hwsrc="00:00:02:00:00:01",
+ hwdst="00:00:02:00:00:01", pdst="48.0.0.1") <1>
+
+----
+<1> G ARP packet with TRex port 1 MAC and IP no need a VM.
+
+[NOTE]
+=====================================================================
+This principal can be done for IPv6 too. ARP could be replaced with Neighbor Solicitation IPv6 packet.
+=====================================================================
+
+==== Tutorial: Field Engine, split to core
+
+Post v2.08 version split to core directive was deprecated and was kept for backward compatibility.
+The new implementation is always to split as if the profile was sent from one core.
+The user of TRex is oblivious to the number of cores.
+
+
+[source,python]
+----
+ def create_stream (self):
+
+ # TCP SYN
+ base_pkt = Ether()/IP(dst="48.0.0.1")/TCP(dport=80,flags="S")
+
+
+ # vm
+ vm = STLScVmRaw( [ STLVmFlowVar(name="ip_src",
+ min_value="16.0.0.0",
+ max_value="16.0.0.254",
+ size=4, op="inc"),
+
+
+ STLVmWrFlowVar(fv_name="ip_src", pkt_offset= "IP.src" ),
+
+ STLVmFixIpv4(offset = "IP"), # fix checksum
+ ]
+ ,split_by_field = "ip_src" <1>
+ )
+
+----
+<1> Deprecated split by field. not used any more (post v2.08)
+
+
+*Some rules regarding split stream variables and burst/multi-burst*::
+
+* When using burst/multi-burst, the number of packets are split to the defualt number of threads specified in the YAML cofiguraiton file, without any need to explicitly split the threads.
+* When the number of packets in a burst is smaller than the number of threads, one thread handles the burst.
+* In the case of a stream with a burst of *1* packet, only the first DP thread handles the stream.
+
+==== Tutorial: Field Engine, Null stream
+
+The following example creates a stream with no packets. The example uses the inter-stream gap (ISG) of the Null stream, and then starts a new stream. Essentially, this uses one property of the stream (ISG) without actually including packets in the stream.
+
+This method can create loops like the following:
+
+image::images/stl_null_stream_02.png[title="Null stream",align="left",width={p_width_1}, link="images/stl_null_stream_02.png"]
+
+1. S1 - Sends a burst of packets, then proceed to stream NULL.
+2. NULL - Waits the inter-stream gap (ISG) time, then proceed to S1.
+
+Null stream configuration:
+
+1. Mode: Burst
+2. Number of packets: 0
+
+
+==== Tutorial: Field Engine, Stream Barrier (Split)
+
+*(Future Feature - not yet implemented)*
+
+In some situations, it is necessary to split streams into threads in such a way that specific streams will continue only after all the threads have passed the same path. In the figure below, a barrier ensures that stream S3 starts only after all threads of S2 are complete.
+
+image::images/stl_barrier_03.png[title="Stream Barrier",align="left",width={p_width}, link="images/stl_barrier_03.png"]
+
+==== Tutorial: PCAP file to one stream
+
+*Goal*:: Load a stream template packet from a pcap file instead of Scapy.
+
+Assumption: The pcap file contains only one packet. If the pcap file contains more than one packet, this procedure loads only the first packet.
+
+*File*:: link:{github_stl_path}/udp_1pkt_pcap.py[stl/udp_1pkt_pcap.py]
+
+[source,python]
+----
+
+ def get_streams (self, direction = 0, **kwargs):
+ return [STLStream(packet =
+ STLPktBuilder(pkt ="stl/yaml/udp_64B_no_crc.pcap"), # path relative to pwd <1>
+ mode = STLTXCont(pps=10)) ]
+
+----
+<1> Takes the packet from the pcap file, relative to the directory in which you are running the script.
+
+
+*File*:: link:{github_stl_path}/udp_1pkt_pcap_relative_path.py[udp_1pkt_pcap_relative_path.py]
+
+
+[source,python]
+----
+
+ def get_streams (self, direction = 0, **kwargs):
+ return [STLStream(packet = STLPktBuilder(pkt ="yaml/udp_64B_no_crc.pcap",
+ path_relative_to_profile = True), <1>
+ mode = STLTXCont(pps=10)) ]
+
+----
+<1> Takes the packet from the pcap file, relative to the directory of the *profile* file location.
+
+
+
+==== Tutorial: Teredo tunnel (IPv6 over IPv4)
+
+The following example demonstrates creating an IPv6 packet within an IPv4 packet, and creating a range of IP addresses.
+
+*File*:: link:{github_stl_path}/udp_1pkt_ipv6_in_ipv4.py[stl/udp_1pkt_ipv6_in_ipv4.py]
+
+[source,python]
+----
+ def create_stream (self):
+ # Teredo Ipv6 over Ipv4
+ pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/
+ UDP(dport=3797,sport=3544)/
+ IPv6(dst="2001:0:4137:9350:8000:f12a:b9c8:2815",
+ src="2001:4860:0:2001::68")/
+ UDP(dport=12,sport=1025)/ICMPv6Unknown()
+
+ vm = STLScVmRaw( [
+ # tuple gen for inner Ipv6
+ STLVmTupleGen ( ip_min="16.0.0.1", ip_max="16.0.0.2",
+ port_min=1025, port_max=65535,
+ name="tuple"), <1>
+
+ STLVmWrFlowVar (fv_name="tuple.ip",
+ pkt_offset= "IPv6.src",
+ offset_fixup=12 ), <2>
+ STLVmWrFlowVar (fv_name="tuple.port",
+ pkt_offset= "UDP:1.sport" ) <3>
+ ]
+ )
+----
+<1> Defines a stream struct called tuple with the following variables: `tuple.ip`, `tuple.port`
+<2> Writes a stream `tuple.ip` variable with an offset determined by the `IPv6.src` offset plus the `offset_fixup` of 12 bytes (only 4 LSB).
+<3> Writes a stream `tuple.port` variable into the second UDP header.
+
+
+==== Tutorial: Mask instruction
+
+STLVmWrMaskFlowVar is single-instruction-multiple-data Field Engine instruction. The pseudocode is as follows:
+
+.Pseudocode
+[source,bash]
+----
+ uint32_t val=(cast_to_size)rd_from_variable("name") # read flow-var
+ val+=m_add_value # add value
+
+ if (m_shift>0) { # shift
+ val=val<<m_shift
+ }else{
+ if (m_shift<0) {
+ val=val>>(-m_shift)
+ }
+ }
+
+ pkt_val=rd_from_pkt(pkt_offset) # RMW
+ pkt_val = (pkt_val & ~m_mask) | (val & m_mask)
+ wr_to_pkt(pkt_offset,pkt_val)
+----
+
+
+*Example 1*::
+
+In this example, STLVmWrMaskFlowVar casts a stream variable with 2 bytes to be 1 byte.
+
+[source,python]
+----
+ vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src",
+ min_value=1,
+ max_value=30,
+ size=2, op="dec",step=1),
+ STLVmWrMaskFlowVar(fv_name="mac_src",
+ pkt_offset= 11,
+ pkt_cast_size=1,
+ mask=0xff) # mask command ->write it as one byte
+ ]
+ )
+
+----
+
+
+*Example 2*::
+
+In this example, STLVmWrMaskFlowVar shifts a variable by 8, which effectively multiplies by 256.
+
+[source,python]
+----
+
+ vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src",
+ min_value=1,
+ max_value=30,
+ size=2, op="dec",step=1),
+ STLVmWrMaskFlowVar(fv_name="mac_src",
+ pkt_offset= 10,
+ pkt_cast_size=2,
+ mask=0xff00,
+ shift=8) # take the var shift it 8 (x256) write only to LSB
+ ]
+ )
+----
+
+
+.Output
+[format="csv",cols="1^", options="header",width="20%"]
+|=================
+ value
+ 0x0100
+ 0x0200
+ 0x0300
+|=================
+
+*Example 3*::
+
+In this example, STLVmWrMaskFlowVar instruction to generate the values shown in the table below as offset values for `pkt_offset`.
+
+[source,python]
+----
+ vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src",
+ min_value=1,
+ max_value=30,
+ size=2,
+ op="dec",step=1),
+ STLVmWrMaskFlowVar(fv_name="mac_src",
+ pkt_offset= 10,
+ pkt_cast_size=1,
+ mask=0x1,
+ shift=-1) <1>
+ ]
+ )
+
+----
+<1> Divides the value of `mac_src` by 2, and writes the LSB. For every two packets, the value written is changed.
+
+.Output
+[format="csv",cols="1^", options="header",width="20%"]
+|=================
+value
+ 0x00
+ 0x00
+ 0x01
+ 0x01
+ 0x00
+ 0x00
+ 0x01
+ 0x01
+|=================
+
+==== Tutorial: Advanced traffic profile
+
+*Goal*::
+
+* Define a different profile to operate in each traffic direction.
+* Define a different profile for each port.
+* Tune a profile tune by the arguments of tunables.
+
+Every traffic profile must define the following function:
+
+[source,python]
+----
+def get_streams (self, direction = 0, **kwargs)
+----
+
+`direction` is a mandatory field, required for any profile being loaded.
+
+A profile can be given any key-value pairs which can be used to customize this profile. These are called "tunables".
+
+The profile defines which tunables can be input to customize output.
+
+*Usage notes for defining parameters*::
+
+* All parameters require default values.
+* A profile must be loadable with no parameters specified.
+* **kwargs (see Python documentation for information about keyworded arguments) contain all of the automatically provided values which are not tunables.
+* Every tuanble must be expressed as key-value pair with default value.
+
+
+For example, for the profile below, 'pcap_with_vm.py':
+
+* The profile receives 'direction' as a tunable and mandatory field.
+* The profile defines 4 additional tunables.
+* Automatic values such as 'port_id' which are not tunables will be provided on kwargs.
+
+
+*File*:: link:{github_stl_path}/pcap_with_vm.py[stl/pcap_with_vm.py]
+
+[source,python]
+----
+def get_streams (self,
+ direction = 0,
+ ipg_usec = 10.0,
+ loop_count = 5,
+ ip_src_range = None,
+ ip_dst_range = {'start' : '10.0.0.1', 'end': '10.0.0.254'},
+ **kwargs)
+----
+
+*Direction*::
+`direction` is a tunable that is always provided by the API/console when loading a profile, but it can be overridden by the user. It is used to make the traffic profile more usable - for example, as a bi-directional profile. However, the profile can ignore this parameter.
+
+By default, `direction` is equal to port_id % 2, so *even* numbered ports are provided with ''0'' and the *odd* numbered ports with ''1''.
+
+[source,python]
+----
+def get_streams (self, direction = 0,**kwargs):
+ if direction = 0:
+ rate =100 <1>
+ else:
+ rate =200
+ return [STLHltStream(tcp_src_port_mode = 'decrement',
+ tcp_src_port_count = 10,
+ tcp_src_port = 1234,
+ tcp_dst_port_mode = 'increment',
+ tcp_dst_port_count = 10,
+ tcp_dst_port = 1234,
+ name = 'test_tcp_ranges',
+ direction = direction,
+ rate_pps = rate,
+ ),
+ ]
+----
+<1> Specifies different rates (100 and 200) based on direction.
+
+[source,bash]
+----
+$start -f ex1.py -a
+----
+
+For 4 interfaces:
+
+* Interfaces 0 and 2: direction 0
+* Interfaces 1 and 3: direction 1
+
+The rate changes accordingly.
+
+*Customzing Profiles Using ''port_id''*::
+
+Keyworded arguments (**kwargs) provide default values that are passed along to the profile.
+
+In the following, 'port_id' (port ID for the profile) is a **kwarg. Using port_id, you can define a complex profile based on different ID of ports, providing a different profile for each port.
+
+
+[source,python]
+----
+
+def create_streams (self, direction = 0, **args):
+
+ port_id = args.get('port_id')
+
+ if port_id == 0:
+ return [STLHltStream(tcp_src_port_mode = 'decrement',
+ tcp_src_port_count = 10,
+ tcp_src_port = 1234,
+ tcp_dst_port_mode = 'increment',
+ tcp_dst_port_count = 10,
+ tcp_dst_port = 1234,
+ name = 'test_tcp_ranges',
+ direction = direction,
+ rate_pps = rate,
+ ),
+ ]
+
+ if port_id == 1:
+ return STLHltStream(
+ #enable_auto_detect_instrumentation = '1', # not supported yet
+ ip_dst_addr = '192.168.1.3',
+ ip_dst_count = '1',
+ ip_dst_mode = 'increment',
+ ip_dst_step = '0.0.0.1',
+ ip_src_addr = '192.168.0.3',
+ ip_src_count = '1',
+ ip_src_mode = 'increment',
+ ip_src_step = '0.0.0.1',
+ l3_imix1_ratio = 7,
+ l3_imix1_size = 70,
+ l3_imix2_ratio = 4,
+ l3_imix2_size = 570,
+ l3_imix3_ratio = 1,
+ l3_imix3_size = 1518,
+ l3_protocol = 'ipv4',
+ length_mode = 'imix',
+ #mac_dst_mode = 'discovery', # not supported yet
+ mac_src = '00.00.c0.a8.00.03',
+ mac_src2 = '00.00.c0.a8.01.03',
+ pkts_per_burst = '200000',
+ rate_percent = '0.4',
+ transmit_mode = 'continuous',
+ vlan_id = '1',
+ direction = direction,
+ )
+
+ if port_id = 3:
+ ..
+----
+
+*Full example using the TRex Console*::
+
+The following command displays information about tunables for the pcap_with_vm.py traffic profile.
+
+[source,bash]
+----
+-=TRex Console v1.1=-
+
+Type 'help' or '?' for supported actions
+
+trex>profile -f stl/pcap_with_vm.py
+
+Profile Information:
+
+
+General Information:
+Filename: stl/pcap_with_vm.py
+Stream count: 5
+
+Specific Information:
+Type: Python Module
+Tunables: ['direction = 0', 'ip_src_range = None', 'loop_count = 5', 'ipg_usec = 10.0',
+ "ip_dst_range = {'start': '10.0.0.1', 'end': '10.0.0.254'}"]
+
+trex>
+----
+
+One can provide tunables on all those fields. The following command changes some:
+
+[source,bash]
+----
+trex>start -f stl/pcap_with_vm.py -t ipg_usec=15.0,loop_count=25
+
+Removing all streams from port(s) [0, 1, 2, 3]: [SUCCESS]
+
+
+Attaching 5 streams to port(s) [0]: [SUCCESS]
+
+
+Attaching 5 streams to port(s) [1]: [SUCCESS]
+
+
+Attaching 5 streams to port(s) [2]: [SUCCESS]
+
+
+Attaching 5 streams to port(s) [3]: [SUCCESS]
+
+
+Starting traffic on port(s) [0, 1, 2, 3]: [SUCCESS]
+
+61.10 [ms]
+
+trex>
+----
+
+
+The following command customizes these to different ports:
+
+[source,bash]
+----
+
+trex>start -f stl/pcap_with_vm.py --port 0 1 -t ipg_usec=15.0,loop_count=25#ipg_usec=100,loop_count=300
+
+Removing all streams from port(s) [0, 1]: [SUCCESS]
+
+
+Attaching 5 streams to port(s) [0]: [SUCCESS]
+
+
+Attaching 5 streams to port(s) [1]: [SUCCESS]
+
+
+Starting traffic on port(s) [0, 1]: [SUCCESS]
+
+51.00 [ms]
+
+trex>
+----
+
+
+==== Tutorial: Per stream statistics
+
+* Per stream statistics are implemented using hardware assist when possible (examples: Intel X710/XL710 NIC flow director rules).
+* With other NICs (examples: Intel I350, 82599), per stream statistics are implemented in software.
+* Implementation:
+** User chooses 32-bit packet group ID (pg_id) for each stream that need statistic reporting. Same pg_id can be used for more than one stream. In this case, statistics for all streams with the same pg_id will be combined.
+** The IPv4 identification (or IPv6 flow label in case of IPv6 packet) field of the stream is changed to a value within the reserved range 0xff00 to 0xffff (0xff00 to 0xfffff in case of IPv6). Note that if a stream for which no statistics are needed has an IPv4 Id (or IPv6 flow label) in the reserved range, it is changed (the left bit becomes 0).
+** Software implementation: Hardware rules are used to direct packets from relevant streams to rx thread, where they are counted.
+** Hardware implementation: Hardware rules are inserted to count packets from relevant streams.
+* Summed up statistics (per stream, per port) is sent using a link:http://zguide.zeromq.org/[ZMQ] async channel to clients.
+
+*Limitations*::
+
+* The feature supports following packet types:
+** IPv4 over Ethernet
+** IPv4 with one VLAN tag (except 82599 which does not support this type of packet)
+** IPv6 over Ethernet (except 82599 which does not support this type of packet)
+** IPv6 with one VLAN tag (except 82599 which does not support this type of packet)
+
+* Maximum number of concurrent streams (with different pg_id) on which statistics may be collected: 127
+
+Two examples follow, one using the console and the other using the Python API.
+
+*Console*::
+
+The following simple traffic profile defines 2 streams and configures them with 2 different PG IDs.
+
+*File*:: link:{github_stl_path}/flow_stats.py[stl/flow_stats.py]
+
+[source,python]
+----
+
+class STLS1(object):
+
+ def get_streams (self, direction = 0):
+ return [STLStream(packet = STLPktBuilder(pkt ="stl/yaml/udp_64B_no_crc.pcap"),
+ mode = STLTXCont(pps = 1000),
+ flow_stats = STLFlowStats(pg_id = 7)), <1>
+
+ STLStream(packet = STLPktBuilder(pkt ="stl/yaml/udp_594B_no_crc.pcap"),
+ mode = STLTXCont(pps = 5000),
+ flow_stats = STLFlowStats(pg_id = 12)) <2>
+ ]
+
+
+----
+<1> Assigned to PG ID 7
+<2> Assigned to PG ID 12
+
+The following command injects this to the console and uses the textual user interface (TUI) to display the TRex activity:
+
+[source,bash]
+----
+trex>start -f stl/flow_stats.py --port 0
+
+Removing all streams from port(s) [0]: [SUCCESS]
+
+
+Attaching 2 streams to port(s) [0]: [SUCCESS]
+
+
+Starting traffic on port(s) [0]: [SUCCESS]
+
+155.81 [ms]
+
+trex>tui
+
+Streams Statistics
+
+ PG ID | 12 | 7
+ --------------------------------------------------
+ Tx pps | 5.00 Kpps | 999.29 pps #<1>
+ Tx bps L2 | 23.60 Mbps | 479.66 Kbps
+ Tx bps L1 | 24.40 Mbps | 639.55 Kbps
+ --- | |
+ Rx pps | 5.00 Kpps | 999.29 pps #<2>
+ Rx bps | N/A | N/A #<3>
+ ---- | |
+ opackets | 222496 | 44500
+ ipackets | 222496 | 44500
+ obytes | 131272640 | 2670000
+ ibytes | N/A | N/A #<3>
+ ----- | |
+ tx_pkts | 222.50 Kpkts | 44.50 Kpkts
+ rx_pkts | 222.50 Kpkts | 44.50 Kpkts
+ tx_bytes | 131.27 MB | 2.67 MB
+ rx_bytes | N/A | N/A #<3>
+
+----
+<1> Tx bandwidth of the streams matches the configured values.
+<2> Rx bandwidth (999.29 pps) matches the Tx bandwidth (999.29 pps), indicating that there were no drops.
+<3> RX BPS is not supported on this platform (no hardware support for BPS), so TRex displays N/A.
+
+
+*Flow Stats Using The Python API*::
+
+The Python API example uses the following traffic profile:
+
+[source,python]
+----
+def rx_example (tx_port, rx_port, burst_size):
+
+ # create client
+ c = STLClient()
+
+ try:
+ pkt = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/
+ UDP(dport=12,sport=1025)/IP()/'a_payload_example')
+
+ s1 = STLStream(name = 'rx',
+ packet = pkt,
+ flow_stats = STLFlowStats(pg_id = 5), <1>
+ mode = STLTXSingleBurst(total_pkts = 5000,
+ percentage = 80
+ ))
+
+ # connect to server
+ c.connect()
+
+ # prepare our ports - TX/RX
+ c.reset(ports = [tx_port, rx_port])
+
+ # add the stream to the TX port
+ c.add_streams([s1], ports = [tx_port])
+
+ # start and wait for completion
+ c.start(ports = [tx_port])
+ c.wait_on_traffic(ports = [tx_port])
+
+ # fetch stats for PG ID 5
+ flow_stats = c.get_stats()['flow_stats'].get(5) <2>
+
+ tx_pkts = flow_stats['tx_pkts'].get(tx_port, 0) <2>
+ tx_bytes = flow_stats['tx_bytes'].get(tx_port, 0) <2>
+ rx_pkts = flow_stats['rx_pkts'].get(rx_port, 0) <2>
+
+----
+<1> Configures the stream to use PG ID 5.
+<2> The structure of the object ''flow_stats'' is described below.
+
+==== Tutorial: flow_stats object structure
+
+The flow_stats object is a dictionary whose keys are the configured PG IDs. The next level is a dictionary containing 'tx_pkts', 'tx_bytes', 'rx_pkts', and 'rx_bytes' (on supported HW). Each of these keys contains a dictionary of per port values.
+
+The following shows a flow_stats object for 3 PG IDs after a specific run:
+
+[source,bash]
+----
+{
+ 5: {'rx_pkts' : {0: 0, 1: 0, 2: 500000, 3: 0, 'total': 500000},
+ 'tx_bytes' : {0: 0, 1: 39500000, 2: 0, 3: 0, 'total': 39500000},
+ 'tx_pkts' : {0: 0, 1: 500000, 2: 0, 3: 0, 'total': 500000}},
+
+ 7: {'rx_pkts' : {0: 0, 1: 0, 2: 0, 3: 288, 'total': 288},
+ 'tx_bytes' : {0: 17280, 1: 0, 2: 0, 3: 0, 'total': 17280},
+ 'tx_pkts' : {0: 288, 1: 0, 2: 0, 3: 0, 'total': 288}},
+
+ 12: {'rx_pkts' : {0: 0, 1: 0, 2: 0, 3: 1439, 'total': 1439},
+ 'tx_bytes': {0: 849600, 1: 0, 2: 0, 3: 0, 'total': 849600},
+ 'tx_pkts' : {0: 1440, 1: 0, 2: 0, 3: 0, 'total': 1440}}
+}
+----
+
+
+==== Tutorial: Per stream latency/jitter/packet errors
+
+* Per stream latency/jitter is implemented by software. This is an extension of the per stream statistics. Meaning, whenever you choose to get latency info for a stream, the statistics described
+in the "Per stream statistics" section is also available.
+* Implementation:
+** User chooses 32-bit packet group ID (pg_id) for each stream that need latency reporting. pg_id should be unique per stream.
+** The IPv4 identification field (or IPv6 flow label in case of IPv6 packet) of the stream is changed to some defined constant value (in the reserved range described in the "per stream statistics" section), in order to signal the hardware to pass the stream to software.
+** Last 16 bytes of the packet payload is used to pass needed information. Information contains ID of the stream, packet sequence number (per stream), timestamp of packet transmission.
+
+* Gathered info (per stream) is sent using a link:http://zguide.zeromq.org/[ZMQ] async channel to clients.
+
+*Limitations*::
+
+* The feature supports following packet types:
+** IPv4 over Ethernet
+** IPv4 with one VLAN tag (except 82599 which does not support this type of packet)
+** IPv6 over Ethernet (except 82599 which does not support this type of packet)
+** IPv6 with one VLAN tag (except 82599 which does not support this type of packet)
+* Packets must contain at least 16 bytes of payload.
+* Each stream must have unique pg_id number. This also means that a given "latency collecting" stream can't be transmitted from two interfaces in parallel (internally it means that there are two streams).
+* Maximum number of concurrent streams (with different pg_id) on which latency info may be collected: 128 (This is in addition to the streams which collect per stream statistics).
+* Global multiplier does not apply to this type of stream. The reason is that latency streams are processed by software, so multiplying them might accidently overwhelm the RX core.
+ This means that if you have profile with 1 latency stream, and 1 non latency stream, and you change the traffic multipler, latency stream keeps the same rate. If you want to change
+ the rate of a latency stream, you need to manually edit your profile file. Usually this is not necessary, since normally you stress the system using non latency stream, and (in parallel) measure latency
+ using constant rate latency stream.
+
+[IMPORTANT]
+=====================================
+Latency streams are not supported in full line rate like normal streams. Both from, transmit and receive point of view. This is a design consideration to keep the latency measurement accurate and preserve CPU resource. One of the reason for doing so that in most cases it is enough to have a latency stream not in full rate. For example, if the required latency resolution is 10usec there is no need to send a latency stream in speed higher than 100KPPS- usually queues are built over time, so it is not possible that one packet will have a latency and another packet in the same path will not have the same latency. The none latency stream could be in full line rate (e.g. 100MPPS) to load the DUT while the low speed latency stream will measure this path latency.
+Don't expect the total latency streams rate to be higher than 1-5MPPS
+=====================================
+
+Two examples follow. One using the console and the other using the Python API.
+
+*Console*::
+
+The following simple traffic profile defines 2 streams and configures them with 2 different PG IDs.
+
+*File*:: link:{github_stl_path}/flow_stats_latency.py[stl/flow_stats_latency.py]
+
+[source,python]
+----
+
+class STLS1(object):
+
+ def get_streams (self, direction = 0):
+ return [STLStream(packet = STLPktBuilder(pkt ="stl/yaml/udp_64B_no_crc.pcap"),
+ mode = STLTXCont(pps = 1000),
+ flow_stats = STLFlowLatencyStats(pg_id = 7)), <1>
+
+ STLStream(packet = STLPktBuilder(pkt ="stl/yaml/udp_594B_no_crc.pcap"),
+ mode = STLTXCont(pps = 5000),
+ flow_stats = STLFlowLatencyStats(pg_id = 12)) <2>
+ ]
+
+
+----
+<1> Assigned to PG ID 7 , PPS would be *1000* regardless of the multplier
+<2> Assigned to PG ID 12, PPS would be *5000* regardless of the multplier
+
+The following command injects this to the console and uses the textual user interface (TUI) to display the TRex activity:
+
+[source,bash]
+----
+trex>start -f stl/flow_stats.py --port 0
+
+trex>tui
+
+Latency Statistics (usec)
+
+ PG ID | 7 | 12
+ ----------------------------------------------
+ Max latency | 0 | 0 #<1>
+ Avg latency | 5 | 5 #<2>
+ -- Window -- | |
+ Last (max) | 3 | 4 #<3>
+ Last-1 | 3 | 3
+ Last-2 | 4 | 4
+ Last-3 | 4 | 3
+ Last-4 | 4 | 4
+ Last-5 | 3 | 4
+ Last-6 | 4 | 3
+ Last-7 | 4 | 3
+ Last-8 | 4 | 4
+ Last-9 | 4 | 3
+ --- | |
+ Jitter | 0 | 0 #<4>
+ ---- | |
+ Errors | 0 | 0 #<5>
+
+----
+<1> Maximum latency measured over the stream lifetime (in usec).
+<2> Average latency over the stream lifetime (usec).
+<3> Maximum latency measured between last two data reads from server (We currently read every 0.5 second).
+ Numbers below are maximum latency for previous measuring periods, so we get latency history for last few seconds.
+<4> Jitter of latency measurements.
+<5> Indication of number of errors (it is the sum of seq_too_high and seq_too_low. You can see description in Python API doc below). In the future it will be possible to 'zoom in', to see specific counters.
+ For now, if you need to see specific counters, you can use the Python API.
+
+
+An example of API usage is as follows
+
+*Example File*:: link:{github_stl_examples_path}/stl_flow_latency_stats.py[stl_flow_latency_stats.py]
+
+[source,python]
+----
+
+ stats = c.get_stats()
+
+ flow_stats = stats['flow_stats'].get(5)
+ lat_stats = stats['latency'].get(5) <1>
+
+
+ tx_pkts = flow_stats['tx_pkts'].get(tx_port, 0)
+ tx_bytes = flow_stats['tx_bytes'].get(tx_port, 0)
+ rx_pkts = flow_stats['rx_pkts'].get(rx_port, 0)
+ drops = lat_stats['err_cntrs']['dropped']
+ ooo = lat_stats['err_cntrs']['out_of_order']
+ dup = lat_stats['err_cntrs']['dup']
+ sth = lat_stats['err_cntrs']['seq_too_high']
+ stl = lat_stats['err_cntrs']['seq_too_low']
+ lat = lat_stats['latency']
+ jitter = lat['jitter']
+ avg = lat['average']
+ tot_max = lat['total_max']
+ last_max = lat['last_max']
+ hist = lat ['histogram']
+
+ # lat_stats will be in this format
+
+ latency_stats == {
+ 'err_cntrs':{ # error counters <2>
+ u'dup':0, # Same sequence number was received twice in a row
+ u'out_of_order':0, # Packets received with sequence number too low (We assume it is reorder)
+ u'dropped':0 # Estimate of number of packets that were dropped (using seq number)
+ u'seq_too_high':0, # seq number too high events
+ u'seq_too_low':0, # seq number too low events
+ },
+ 'latency':{
+ 'jitter':0, # in usec
+ 'average':15.2, # average latency (usec)
+ 'last_max':0, # last 0.5 sec window maximum latency (usec)
+ 'total_max':44, # maximum latency (usec)
+ 'histogram':[ # histogram of latency
+ {
+ u'key':20, # bucket counting packets with latency in the range 20 to 30 usec
+ u'val':489342 # number of samples that hit this bucket's range
+ },
+ {
+ u'key':30,
+ u'val':10512
+ },
+ {
+ u'key':40,
+ u'val':143
+ },
+ {
+ 'key':0, # bucket counting packets with latency in the range 0 to 10 usec
+ 'val':3
+ }
+ ]
+ }
+ },
+
+
+----
+<1> Get the Latency dictionary
+<2> For calculating packet error events, we add sequence number to each packet's payload. We decide what went wrong only according to sequence number
+ of last packet received and that of the previous packet. 'seq_too_low' and 'seq_too_high' count events we see. 'dup', 'out_of_order' and 'dropped'
+ are heuristics we apply to try and understand what happened. They will be accurate in common error scenarios.
+ We describe few scenarios below to help understand this. +
+
+*Error counters scenarios*::
+Scenario 1: Received packet with seq num 10, and another one with seq num 10. We increment 'dup' and 'seq_too_low' by 1. +
+Scenario 2: Received pacekt with seq num 10 and then packet with seq num 15. We assume 4 packets were dropped, and increment 'dropped' by 4, and 'seq_too_high' by 1.
+ We expect next packet to arrive with sequence number 16. +
+Scenario 2 continue: Received packet with seq num 11. We increment 'seq_too_low' by 1. We increment 'out_of_order' by 1. We *decrement* 'dropped' by 1.
+ (We assume here that one of the packets we considered as dropped before, actually arrived out of order).
+
+==== Tutorial: HLT traffic profile
+
+The traffic_config API has set of arguments for specifying streams - in particular, the packet template, which field, and how to send it.
+// clarify "which field"
+It is possible to define a traffic profile using HTTAPI arguments.
+// clarify names: "HLT traffic profile", "traffic_config API", "HTTAP"
+The API creates native Scapy/Field Engine instructions.
+For limitations see xref:altapi-support[here].
+
+*File*:: link:{github_stl_path}/hlt/hlt_udp_inc_dec_len_9k.py[stl/hlt/hlt_udp_inc_dec_len_9k.py]
+
+[source,python]
+----
+
+class STLS1(object):
+ '''
+ Create 2 Eth/IP/UDP streams with different packet size:
+ First stream will start from 64 bytes (default) and will increase until max_size (9,216)
+ Seconds stream will decrease the packet size in reverse way
+ '''
+
+ def create_streams (self):
+ max_size = 9*1024
+ return [STLHltStream(length_mode = 'increment',
+ frame_size_max = max_size,
+ l3_protocol = 'ipv4',
+ ip_src_addr = '16.0.0.1',
+ ip_dst_addr = '48.0.0.1',
+ l4_protocol = 'udp',
+ udp_src_port = 1025,
+ udp_dst_port = 12,
+ rate_pps = 1,
+ ),
+ STLHltStream(length_mode = 'decrement',
+ frame_size_max = max_size,
+ l3_protocol = 'ipv4',
+ ip_src_addr = '16.0.0.1',
+ ip_dst_addr = '48.0.0.1',
+ l4_protocol = 'udp',
+ udp_src_port = 1025,
+ udp_dst_port = 12,
+ rate_pps = 1,
+ )
+ ]
+
+ def get_streams (self, direction = 0, **kwargs):
+ return self.create_streams()
+----
+
+The following command, within a bash window, runs the traffic profile with the simulator to generate pcap file.
+
+[source,bash]
+----
+$ ./stl-sim -f stl/hlt/hlt_udp_inc_dec_len_9k.py -o b.pcap -l 10
+----
+
+The following commands, within a bash window, convert to native JSON or YAML.
+
+[source,bash]
+----
+$ ./stl-sim -f stl/hlt/hlt_udp_inc_dec_len_9k.py --json
+----
+
+[source,bash]
+----
+$ ./stl-sim -f stl/hlt/hlt_udp_inc_dec_len_9k.py --yaml
+----
+
+Alternatively, use the following command to convert to a native Python profile.
+
+[source,bash]
+----
+$ ./stl-sim -f stl/hlt/hlt_udp_inc_dec_len_9k.py --native
+----
+
+.Auto-generated code
+[source,python]
+----
+# !!! Auto-generated code !!!
+from trex_stl_lib.api import *
+
+class STLS1(object):
+ def get_streams(self):
+ streams = []
+
+ packet = (Ether(src='00:00:01:00:00:01', dst='00:00:00:00:00:00', type=2048) /
+ IP(proto=17, chksum=5882, len=9202, ihl=5L, id=0) /
+ UDP(dport=12, sport=1025, len=9182, chksum=55174) /
+ Raw(load='!' * 9174))
+ vm = STLScVmRaw([CTRexVmDescFlowVar(name='pkt_len', size=2, op='inc',
+ init_value=64, min_value=64, max_value=9216, step=1),
+ CTRexVmDescTrimPktSize(fv_name='pkt_len'),
+ CTRexVmDescWrFlowVar(fv_name='pkt_len',
+ pkt_offset=16, add_val=-14, is_big=True),
+ CTRexVmDescWrFlowVar(fv_name='pkt_len',
+ pkt_offset=38, add_val=-34, is_big=True),
+ CTRexVmDescFixIpv4(offset=14)], split_by_field = 'pkt_len')
+ stream = STLStream(packet = CScapyTRexPktBuilder(pkt = packet, vm = vm),
+ mode = STLTXCont(pps = 1.0))
+ streams.append(stream)
+
+ packet = (Ether(src='00:00:01:00:00:01', dst='00:00:00:00:00:00', type=2048) /
+ IP(proto=17, chksum=5882, len=9202, ihl=5L, id=0) /
+ UDP(dport=12, sport=1025, len=9182, chksum=55174) /
+ Raw(load='!' * 9174))
+ vm = STLScVmRaw([CTRexVmDescFlowVar(name='pkt_len', size=2, op='dec',
+ init_value=9216, min_value=64,
+ max_value=9216, step=1),
+ CTRexVmDescTrimPktSize(fv_name='pkt_len'),
+ CTRexVmDescWrFlowVar(fv_name='pkt_len', pkt_offset=16,
+ add_val=-14, is_big=True),
+ CTRexVmDescWrFlowVar(fv_name='pkt_len',
+ pkt_offset=38, add_val=-34, is_big=True),
+ CTRexVmDescFixIpv4(offset=14)], split_by_field = 'pkt_len')
+ stream = STLStream(packet = CScapyTRexPktBuilder(pkt = packet, vm = vm),
+ mode = STLTXCont(pps = 1.0))
+ streams.append(stream)
+
+ return streams
+
+def register():
+ return STLS1()
+----
+
+Use the following command within the TRex console to run the profile.
+
+[source,bash]
+----
+TRex>start -f stl/hlt/hlt_udp_inc_dec_len_9k.py -m 10mbps -a
+----
+
+
+=== PCAP Based Traffic Tutorials
+
+==== PCAP Based Traffic
+
+TRex provides a method of using a pre-recorded traffic as a profile template.
+
+There are two main distinct ways of creating a profile or a test based on a PCAP.
+
+* Local PCAP push
+* Server based push
+
+===== Local PCAP push
+
+On this mode, the PCAP file is loaded locally by the Python client,
+transformed to a list of streams which each one contains a single packet
+and points to the next one.
+
+This allows of a very flexible structure which can basically provide every
+functionality that a regular list of streams allow.
+
+However, due to the overhead of processing and
+sending a list of streams this method is limited to a file size (on default 1MB)
+
+
+*Pros:*
+
+* supports most CAP file formats
+* supports field engine
+* provides a way of locally manipulating packets as streams
+* supports same rate as regular streams
+
+*Cons:*
+
+* limited in file size
+* high configuration time due to transmitting the CAP file as streams
+
+
+===== Server based push
+
+To provide also a way of injecting a much larger PCAP files, TRex also provides
+a server based push.
+
+The mechansim is much different and it simply providing a server a PCAP file which
+in turn is loaded to the server and injected packet after packet.
+
+This method provides an unlimited file size to be injected, and the overhead of
+setting up the server with the required configuration is much lower.
+
+
+*Pros:*
+
+* no limitation of PCAP file size
+* no overhead in sending any size of PCAP to the server
+
+*Cons:*
+
+* does not support field engine
+* support only PCAP and ERF formats
+* requires the file path to be accessible from the server
+* rate of transmition is usually limited by I/O performance and buffering (HDD)
+
+
+==== Tutorial: Simple PCAP file - Profile
+
+*Goal*:: Load a pcap file with a *number* of packets, creating a stream with a burst value of 1 for each packet. The inter-stream gap (ISG) for each stream is equal to the inter-packet gap (IPG).
+
+*File*:: link:{github_stl_path}/pcap.py[pcap.py]
+
+[source,python]
+----
+ def get_streams (self,
+ ipg_usec = 10.0, <1>
+ loop_count = 1): <2>
+
+ profile = STLProfile.load_pcap(self.pcap_file, <3>
+ ipg_usec = ipg_usec,
+ loop_count = loop_count)
+----
+<1> The inter-stream gap in microseconds.
+<2> Loop count.
+<3> Input pcap file.
+
+// Please leave this comment - helping rendition.
+
+image::images/stl_loop_count_01b.png[title="Example of multiple streams",align="left",width="80%", link="images/stl_loop_count_01b.png"]
+
+// OBSOLETE: image::images/stl_loop_count_01b.png[title="Streams, loop_count",align="left",width={p_width_1a}, link="images/stl_loop_count_01b.png"]
+
+The figure shows the streams for a pcap file with 3 packets, with a loop configured.
+
+* Each stream is configured to Burst mode with 1 packet.
+* Each stream triggers the next stream.
+* The last stream triggers the first with `action_loop=loop_count` if `loop_count` > 1.
+
+The profile runs on one DP thread because it has a burst with 1 packet. (Split cannot work in this case).
+
+To run this example, enter:
+
+[source,bash]
+----
+./stl-sim -f stl/pcap.py --yaml
+----
+
+The following output appears:
+
+[source,python]
+----
+$./stl-sim -f stl/pcap.py --yaml
+- name: 1
+ next: 2 <1>
+ stream:
+ action_count: 0
+ enabled: true
+ flags: 0
+ isg: 10.0
+ mode:
+ percentage: 100
+ total_pkts: 1
+ type: single_burst
+ packet:
+ meta: ''
+ rx_stats:
+ enabled: false
+ self_start: true
+ vm:
+ instructions: []
+ split_by_var: ''
+- name: 2
+ next: 3
+ stream:
+ action_count: 0
+ enabled: true
+ flags: 0
+ isg: 10.0
+ mode:
+ percentage: 100
+ total_pkts: 1
+ type: single_burst
+ packet:
+ meta: ''
+ rx_stats:
+ enabled: false
+ self_start: false
+ vm:
+ instructions: []
+ split_by_var: ''
+- name: 3
+ next: 4
+ stream:
+ action_count: 0
+ enabled: true
+ flags: 0
+ isg: 10.0
+ mode:
+ percentage: 100
+ total_pkts: 1
+ type: single_burst
+ packet:
+ meta: ''
+ rx_stats:
+ enabled: false
+ self_start: false
+ vm:
+ instructions: []
+ split_by_var: ''
+- name: 4
+ next: 5
+ stream:
+ action_count: 0
+ enabled: true
+ flags: 0
+ isg: 10.0
+ mode:
+ percentage: 100
+ total_pkts: 1
+ type: single_burst
+ packet:
+ meta: ''
+ rx_stats:
+ enabled: false
+ self_start: false
+ vm:
+ instructions: []
+ split_by_var: ''
+- name: 5
+ next: 1 <2>
+ stream:
+ action_count: 1 <3>
+ enabled: true
+ flags: 0
+ isg: 10.0
+ mode:
+ percentage: 100
+ total_pkts: 1
+ type: single_burst
+ packet:
+ meta: ''
+ rx_stats:
+ enabled: false
+ self_start: false <4>
+ vm:
+ instructions: []
+ split_by_var: ''
+----
+<1> Each stream triggers the next stream.
+<2> The last stream triggers the first.
+<3> The current loop count is given in: `action_count: 1`
+<4> `Self_start` is enabled for the first stream, disabled for all other streams.
+
+
+==== Tutorial: Simple PCAP file - API
+
+For this case we can use the local push:
+
+[source,bash]
+----
+c = STLClient(server = "localhost")
+
+try:
+
+ c.connect()
+ c.reset(ports = [0])
+
+ d = c.push_pcap(pcap_file = "my_file.pcap", # our local PCAP file
+ ports = 0, # use port 0
+ ipg_usec = 100, # IPG
+ count = 1) # inject only once
+
+ c.wait_on_traffic()
+
+
+ stats = c.get_stats()
+ opackets = stats[port]['opackets']
+ print("{0} packets were Tx on port {1}\n".format(opackets, port))
+
+ except STLError as e:
+ print(e)
+ sys.exit(1)
+
+ finally:
+ c.disconnect()
+
+----
+
+==== Tutorial: PCAP file iterating over dest IP
+
+For this case we can use the local push:
+
+[source,bash]
+----
+c = STLClient(server = "localhost")
+
+try:
+
+ c.connect()
+ port = 0
+ c.reset(ports = [port])
+
+ vm = STLIPRange(dst = {'start': '10.0.0.1', 'end': '10.0.0.254', 'step' : 1})
+
+ c.push_pcap(pcap_file = "my_file.pcap", # our local PCAP file
+ ports = port, # use 'port'
+ ipg_usec = 100, # IPG
+ count = 1, # inject only once
+ vm = vm # provide VM object
+ )
+
+ c.wait_on_traffic()
+
+ stats = c.get_stats()
+ opackets = stats[port]['opackets']
+ print("{0} packets were Tx on port {1}\n".format(opackets, port))
+
+ except STLError as e:
+ print(e)
+ sys.exit(1)
+
+ finally:
+ c.disconnect()
+
+----
+
+==== Tutorial: PCAP file with VLAN
+
+This is a more intresting case where we can provide the push API a function hook.
+The hook will be called for each packet that is loaded from the PCAP file.
+
+[source,bash]
+----
+# generate a packet hook function with a VLAN ID
+def packet_hook_generator (vlan_id):
+
+ # this function will be called for each packet and will expect
+ # the new packet as a return value
+ def packet_hook (packet):
+ packet = Ether(packet)
+
+ if vlan_id >= 0 and vlan_id <= 4096:
+ packet_l3 = packet.payload
+ packet = Ether() / Dot1Q(vlan = vlan_id) / packet_l3
+
+ return str(packet)
+
+ return packet_hook
+
+c = STLClient(server = "localhost")
+
+try:
+
+ c.connect()
+ port = 0
+ c.reset(ports = [port])
+
+ vm = STLIPRange(dst = {'start': '10.0.0.1', 'end': '10.0.0.254', 'step' : 1})
+
+ d = c.push_pcap(pcap_file = "my_file.pcap",
+ ports = port,
+ ipg_usec = 100,
+ count = 1,
+ packet_hook = packet_hook_generator(vlan_id = 1)
+ )
+
+ c.wait_on_traffic()
+
+ stats = c.get_stats()
+ opackets = stats[port]['opackets']
+ print("{0} packets were Tx on port {1}\n".format(opackets, port))
+
+ except STLError as e:
+ print(e)
+ sys.exit(1)
+
+ finally:
+ c.disconnect()
+
+----
+
+==== Tutorial: PCAP file and Field Engine - Profile
+
+The following example loads a pcap file to many streams, and attaches Field Engine program to each stream. For example, the Field Engine can change the `IP.src` of all the streams to a random IP address.
+
+*File*:: link:{github_stl_path}/pcap_with_vm.py[stl/pcap_with_vm.py]
+
+[source,python]
+----
+
+ def create_vm (self, ip_src_range, ip_dst_range):
+ if not ip_src_range and not ip_dst_range:
+ return None
+
+ # until the feature of offsets will be fixed for PCAP use hard coded offsets
+
+ vm = []
+
+ if ip_src_range:
+ vm += [STLVmFlowVar(name="src",
+ min_value = ip_src_range['start'],
+ max_value = ip_src_range['end'],
+ size = 4, op = "inc"),
+ #STLVmWrFlowVar(fv_name="src",pkt_offset= "IP.src")
+ STLVmWrFlowVar(fv_name="src",pkt_offset = 26)
+ ]
+
+ if ip_dst_range:
+ vm += [STLVmFlowVar(name="dst",
+ min_value = ip_dst_range['start'],
+ max_value = ip_dst_range['end'],
+ size = 4, op = "inc"),
+
+ #STLVmWrFlowVar(fv_name="dst",pkt_offset= "IP.dst")
+ STLVmWrFlowVar(fv_name="dst",pkt_offset = 30)
+ ]
+
+ vm += [#STLVmFixIpv4(offset = "IP")
+ STLVmFixIpv4(offset = 14)
+ ]
+
+ return vm
+
+
+ def get_streams (self,
+ ipg_usec = 10.0,
+ loop_count = 5,
+ ip_src_range = None,
+ ip_dst_range = {'start' : '10.0.0.1',
+ 'end': '10.0.0.254'}):
+
+ vm = self.create_vm(ip_src_range, ip_dst_range) <1>
+ profile = STLProfile.load_pcap(self.pcap_file,
+ ipg_usec = ipg_usec,
+ loop_count = loop_count,
+ vm = vm) <2>
+
+ return profile.get_streams()
+----
+<1> Creates Field Engine program.
+<2> Applies the Field Engine to all packets -> converts to streams.
+
+.Output
+[format="csv",cols="1^,2^,1^", options="header",width="40%"]
+|=================
+pkt, IPv4 , flow
+ 1 , 10.0.0.1, 1
+ 2 , 10.0.0.1, 1
+ 3 , 10.0.0.1, 1
+ 4 , 10.0.0.1, 1
+ 5 , 10.0.0.1, 1
+ 6 , 10.0.0.1, 1
+ 7 , 10.0.0.2, 2
+ 8 , 10.0.0.2, 2
+ 9 , 10.0.0.2, 2
+ 10 , 10.0.0.2,2
+ 11 , 10.0.0.2,2
+ 12 , 10.0.0.2,2
+|=================
+
+
+==== Tutorial: Huge server side PCAP file
+
+Now we would like to use the remote push API.
+This will require the file path to be visible to the server.
+
+[source,bash]
+----
+c = STLClient(server = "localhost")
+
+try:
+
+ c.connect()
+ c.reset(ports = [0])
+
+ # use an absolute path so the server can reach this
+ pcap_file = os.path.abspath(pcap_file)
+
+ c.push_remote(pcap_file = pcap_file,
+ ports = 0,
+ ipg_usec = 100,
+ count = 1)
+
+ c.wait_on_traffic()
+
+
+ stats = c.get_stats()
+ opackets = stats[port]['opackets']
+ print("{0} packets were Tx on port {1}\n".format(opackets, port))
+
+ except STLError as e:
+ print(e)
+ sys.exit(1)
+
+ finally:
+ c.disconnect()
+
+----
+
+==== Tutorial: A long list of PCAP files of varied sizes
+
+This is also a good candidate for the remote push API.
+The total overhead for sending the PCAP files will be high if the list is long,
+so we would prefer to inject them with remote API and to save the transmition of the packets.
+
+[source,bash]
+----
+c = STLClient(server = "localhost")
+
+try:
+
+ c.connect()
+ c.reset(ports = [0])
+
+ # iterate over the list and send each file to the server
+ for pcap_file in pcap_file_list:
+ pcap_file = os.path.abspath(pcap_file)
+
+ c.push_remote(pcap_file = pcap_file,
+ ports = 0,
+ ipg_usec = 100,
+ count = 1)
+
+ c.wait_on_traffic()
+
+
+ stats = c.get_stats()
+ opackets = stats[port]['opackets']
+ print("{0} packets were Tx on port {1}\n".format(opackets, port))
+
+ except STLError as e:
+ print(e)
+ sys.exit(1)
+
+ finally:
+ c.disconnect()
+
+----
+
+=== Performance Tweaking
+In this section we provide some advanced features to help get the most of TRex performance.
+The reason that those features are not active out of the box because they might have
+some impact on other areas and in general, might sacrafice one or more properties
+that requires the user to explicitly give up on those.
+
+==== Caching MBUFs
+
+
+see xref:trex_cache_mbuf[here]
+
+
+==== Core masking per interface
+By default, TRex will regard any TX command with a **greedy approach**:
+All the DP cores associated with this port will be assigned in order to produce the maximum
+throughput.
+
+image::images/core_mask_split.png[title="Greedy Approach - Splitting",align="left",width={p_width}, link="images/core_mask_split.png"]
+
+However, in some cases it might be beneficial to provide a port with a subset of the cores to use.
+
+
+For example, when injecting traffic on two ports and the following conditions are met:
+
+* the two ports are adjacent
+* the profile is symmetric
+
+Due to TRex architecture, adjacent ports (e.g. port 0 & port 1) shares the same cores,
+and using the greedy approach will cause all the cores to transmit on both port 0 and port 1.
+
+When the profile is *symmetric* it will be wiser to pin half the cores to port 0 and half
+the cores to port 1 and thus avoid cache trashing and bouncing.
+If the profile is not symmetric, the static pinning may deny CPU cycles from the more congested port.
+
+image::images/core_mask_pin.png[title="Pinning Cores To Ports",align="left",width={p_width}, link="images/core_mask_pin.png"]
+
+TRex provides this in two ways:
+
+
+==== Predefind modes
+
+As said above, the default mode is 'split' mode, but you can provide a predefined mode called 'pin'.
+This can be done by both API and from the console:
+
+[source,bash]
+----
+
+trex>start -f stl/syn_attack.py -m 40mpps --total -p 0 1 --pin <-- provide '--pin' to the command
+
+Removing all streams from port(s) [0, 1]: [SUCCESS]
+
+
+Attaching 1 streams to port(s) [0]: [SUCCESS]
+
+
+Attaching 1 streams to port(s) [1]: [SUCCESS]
+
+
+Starting traffic on port(s) [0, 1]: [SUCCESS]
+
+60.20 [ms]
+
+trex>
+
+----
+
+
+.API example to PIN cores
+[source,python]
+----
+ c.start(ports = [port_a, port_b], mult = rate,core_mask=STLClient.CORE_MASK_PIN) <1>
+----
+<1> core_mask = STLClient.CORE_MASK_PIN
+
+.API example to MASK cores
+[source,python]
+----
+ c.start(ports = [port_a, port_b], mult = rate, core_mask=[0x1,0x2])<1>
+----
+<1> DP Core 0 (mask==1) is assign to port 1 and DP core 1 (mask==2) is for port 2
+
+
+[source,bash]
+----
+
+We can see in the CPU util. available from the TUI window,
+that each core was reserverd for an interface:
+
+Global Stats:
+
+Total Tx L2 : 20.49 Gb/sec
+Total Tx L1 : 26.89 Gb/sec
+Total Rx : 20.49 Gb/sec
+Total Pps : 40.01 Mpkt/sec <-- performance meets the requested rate
+Drop Rate : 0.00 b/sec
+Queue Full : 0 pkts
+
+
+Cpu Util(%)
+
+ Thread | Avg | Latest | -1 | -2 | -3 | -4 | -5 | -6 | -7 | -8
+
+ 0 (0) | 92 | 92 | 92 | 91 | 91 | 92 | 91 | 92 | 93 | 94
+ 1 (IDLE) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+ 2 (1) | 96 | 95 | 95 | 96 | 96 | 96 | 96 | 95 | 94 | 95
+ 3 (IDLE) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+ 4 (0) | 92 | 93 | 93 | 91 | 91 | 93 | 93 | 93 | 93 | 93
+ 5 (IDLE) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+ 6 (1) | 88 | 88 | 88 | 88 | 88 | 88 | 88 | 88 | 87 | 87
+ 7 (IDLE) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+
+----
+
+
+If we had used the *default mode*, the table should have looked like this, and yield
+much worse performance:
+
+[source,bash]
+----
+
+Global Stats:
+
+Total Tx L2 : 12.34 Gb/sec
+Total Tx L1 : 16.19 Gb/sec
+Total Rx : 12.34 Gb/sec
+Total Pps : 24.09 Mpkt/sec <-- performance is quite low than requested
+Drop Rate : 0.00 b/sec
+Queue Full : 0 pkts
+
+Cpu Util(%)
+
+ Thread | Avg | Latest | -1 | -2 | -3 | -4 | -5 | -6 | -7 | -8
+
+ 0 (0,1) | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100
+ 1 (IDLE) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+ 2 (0,1) | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100
+ 3 (IDLE) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+ 4 (0,1) | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100
+ 5 (IDLE) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+ 6 (0,1) | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100
+ 7 (IDLE) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+
+----
+
+This feature is also available from the Python API by providing:
+*CORE_MASK_SPLIT* or *CORE_MASK_PIN* to the start API.
+
+
+==== Manual mask
+Sometimes for debug purposes or for a more advanced core scheduling you might want
+to provide a manual masking that will guide the server on which cores to use.
+
+For example, let's assume we have a profile that utilize 95% of the traffic on one side,
+and in the other direction it provides 5% of the traffic.
+Let's assume also we have 8 cores assigned to the two interfaces.
+
+We want to assign 3 cores to interface 0 and 1 core only to interface 1.
+
+We can provide this line to the console (or for the API by providing a list of masks to the start
+command):
+
+[source,bash]
+----
+trex>start -f stl/syn_attack.py -m 10mpps --total -p 0 1 --core_mask 0xE 0x1
+
+Removing all streams from port(s) [0, 1]: [SUCCESS]
+
+
+Attaching 1 streams to port(s) [0]: [SUCCESS]
+
+
+Attaching 1 streams to port(s) [1]: [SUCCESS]
+
+
+Starting traffic on port(s) [0, 1]: [SUCCESS]
+
+37.19 [ms]
+
+trex>
+----
+
+[source,python]
+----
+ c.start(ports = [port_a, port_b], mult = rate,core_mask=[0x0xe,0x1]) <1>
+----
+<1> mask of cores per port
+
+
+
+The following output is received on the TUI CPU util window:
+
+[source,bash]
+----
+
+Total Tx L2 : 5.12 Gb/sec
+Total Tx L1 : 6.72 Gb/sec
+Total Rx : 5.12 Gb/sec
+Total Pps : 10.00 Mpkt/sec
+Drop Rate : 0.00 b/sec
+Queue Full : 0 pkts
+
+Cpu Util(%)
+
+ Thread | Avg | Latest | -1 | -2 | -3 | -4 | -5 | -6 | -7 | -8
+
+ 0 (1) | 45 | 45 | 45 | 45 | 45 | 45 | 46 | 45 | 46 | 45
+ 1 (IDLE) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+ 2 (0) | 15 | 15 | 14 | 15 | 15 | 14 | 14 | 14 | 14 | 14
+ 3 (IDLE) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+ 4 (0) | 14 | 14 | 14 | 14 | 14 | 14 | 14 | 14 | 15 | 14
+ 5 (IDLE) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+ 6 (0) | 15 | 15 | 15 | 15 | 15 | 15 | 15 | 15 | 15 | 15
+ 7 (IDLE) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
+
+----
+
+=== Reference
+
+Additional profiles and examples are available in the `stl/hlt` folder.
+
+For information about the Python client API, see the link:cp_stl_docs/index.html[Python Client API documentation].
+
+=== Console commands
+
+==== Overview
+
+The console uses TRex client API to control TRex.
+
+*Important information about console usage*::
+
+// it seems that all of these provide background info, not guidelines for use. the use of "should" is unclear.
+
+* The console does not save its own state. It caches the server state. It is assumed that there is only one console with R/W permission at any given time, so once connected as R/W console (per user/interface), it can read the server state and then cache all operations.
+* Many read-only clients can exist for the same user interface.
+* The console syncs with the server to get the state during connection stage, and caches the server information locally.
+* In case of crash or exit of the console, it will sync again at startup.
+* Command line parameters order is not important.
+* The console can display TRex stats in real time. You can open two consoles simultaneously - one for commands (R/W) and one for displaying statistics (read only).
+
+==== Ports State
+
+[options="header",cols="^1,3a"]
+|=================
+| state | meaning
+| IDLE | No streams
+| STREAMS | Has streams. Not transmitting (did not start transmission, or it was stopped).
+| WORK | Has streams. Transmitting.
+| PAUSE | Has streams. Transmission paused.
+|=================
+
+
+[source,bash]
+----
+
+ IDLE -> (add streams) -> STREAMS (start) -> WORK (stop) -> STREAMS (start)
+ | WORK (pause) -> PAUSE (resume )---
+ | |
+ | |
+ --------------------------------------
+----
+
+==== Common Arguments
+
+Following command line arguments are common to many commands.
+
+===== Help
+You can specify -h or --help after each command to get full description of its purpose and arguments.
+
+*Example*::
+
+[source,bash]
+----
+$streams -h
+----
+
+===== Port mask
+
+Port mask enables selecting range, or set of ports.
+
+*Example*::
+
+[source,bash]
+----
+$<command> [-a] [--port 1 2 3] [--port 0xff] [--port clients/servers]
+
+ port mask :
+ [-a] : all ports
+ [--port 1 2 3] : port 1,2 3
+ [--port 0xff] : port by mask 0x1 for port 0 0x3 for port 0 and 1
+----
+
+===== Duration
+
+Duration is expressed in seconds, minutes, or hours.
+
+*Example*::
+
+[source,bash]
+----
+$<command> [-d 100] [-d 10m] [-d 1h]
+
+ duration:
+ -d 100 : Seconds
+ -d 10m : Minutes
+ -d 1h : Hours
+----
+
+
+===== Multiplier
+
+The traffic profile defines default bandwidth for each stream. Using the multiplier command line argument, it is possible to set different bandwidth. It is possible to specify either packets or bytes per second, percentage of total port rate, or just factor to multiply the original rate by.
+
+*Example*::
+
+[source,bash]
+----
+$<command> [-m 100] [-m 10gb] [-m 10kpps] [-m 40%]
+
+ multiplier :
+
+ -m 100 : Multiply original rate by given factor.
+ -m 10gbps : From graph calculate the maximum rate as this bandwidth for all streams( for each port )
+ -m 10kpps : From graph calculate the maximum rate as this pps for all streams ( for each port )
+ -m 40% : From graph calculate the maximum rate as this precent from total port rate ( for each port )
+----
+// What does it mean from graph???
+
+
+==== Commands
+
+===== connect
+
+Attempts to connet to the server you were connected to. Can be used in case server was restarted. Can not be used
+in order to connect to different server. In addition:
+
+* Syncs the port info and stream info state.
+* Reads all counter statistics for reference.
+
+// IGNORE: this line helps rendering of next line
+
+*Example*::
+
+[source,bash]
+----
+$connect
+----
+
+===== reset
+
+Resets the server and client to a known state. Not used in normal scenarios.
+
+- Forces acquire on all ports
+- Stops all traffic on all ports
+- Removes all streams from all ports
+
+
+*Example*::
+
+[source,bash]
+----
+$reset
+----
+
+===== portattr
+
+Configures port attributes.
+
+*Example*::
+
+[source,python]
+----
+$portattr --help
+usage: port_attr [-h] [--port PORTS [PORTS ...] | -a] [--prom {on,off}]
+ [--link {up,down}] [--led {on,off}] [--fc {none,tx,rx,full}]
+ [--supp]
+
+Sets port attributes
+
+optional arguments:
+ -h, --help show this help message and exit
+ --port PORTS [PORTS ...], -p PORTS [PORTS ...]
+ A list of ports on which to apply the command
+ -a Set this flag to apply the command on all available
+ ports
+ --prom {on,off} Set port promiscuous on/off
+ --link {up,down} Set link status up/down
+ --led {on,off} Set LED status on/off
+ --fc {none,tx,rx,full}
+ Set Flow Control type
+ --supp Show which attributes are supported by current NICs
+----
+
+image::images/console_link_down.png[title="Setting link down on port 0 affects port 1 at loopback"]
+
+
+===== clear
+
+Clears all port stats counters.
+
+*Example*::
+
+[source,bash]
+----
+$clear -a
+----
+
+
+===== stats
+
+Can be used to show global/port/stream statistics. +
+Also, can be used to retrieve extended stats from port (xstats)
+
+*Example*::
+
+[source,bash]
+----
+$stats --port 0 -p
+$stats -s
+----
+
+*Xstats error example*::
+
+[source,bash]
+----
+
+trex>stats -x --port 0 2
+Xstats:
+
+ Name: | Port 0: | Port 2:
+\------------------------------------------------------------------
+rx_good_packets | 154612905 | 153744994
+tx_good_packets | 154612819 | 153745136
+rx_good_bytes | 9895225920 | 9839679168
+tx_good_bytes | 9276768500 | 9224707392
+rx_unicast_packets | 154611873 | 153743952
+rx_unknown_protocol_packets | 154611896 | 153743991
+tx_unicast_packets | 154612229 | 153744562
+mac_remote_errors | 1 | 0 #<1>
+rx_size_64_packets | 154612170 | 153744295
+tx_size_64_packets | 154612595 | 153744902
+
+----
+
+<1> Error that can be seen only with this command
+
+// IGNORE - this line helps rendering
+
+===== streams
+
+Shows info about configured streams on each port, from the client cache.
+
+*Example*::
+
+[source,bash]
+----
+$streams
+
+Port 0:
+
+ ID | packet type | length | mode | rate | next stream
+
+ 1 | Ethernet:IP:UDP:Raw | 64 | continuous | 1 pps | -1
+ 2 | Ethernet:IP:UDP:Raw | 64 | continuous | 1.00 Kpps | -1
+
+Port 1:
+
+ ID | packet type | length | mode | rate | next stream
+
+ 1 | Ethernet:IP:UDP:Raw | 64 | continuous | 1 pps | -1
+ 2 | Ethernet:IP:UDP:Raw | 64 | continuous | 1.00 Kpps | -1
+
+----
+
+
+*Example*::
+
+Use this command to show only ports 1 and 2.
+
+[source,bash]
+----
+$streams --port 1 2
+
+ ..
+ ..
+----
+
+*Example*::
+
+Use this command to show full information for stream 0 and port 0, output in JSON format.
+
+[source,bash]
+----
+$streams --port 0 --streams 0
+
+----
+
+
+===== start
+
+Start transmitting traffic on set of ports
+
+* Removes all streams
+* Loads new streams
+* Starts traffic (can set multiplier, duration and other parameters)
+* Acts only on ports in "stopped: mode. If `--force` is specified, port(s) are first stopped.
+* Note: If any ports are not in "stopped" mode, and `--force` is not used the command fails.
+
+// IGNORE: this line helps rendering of next line
+
+*Example*::
+
+Use this command to start a profile on all ports, with a maximum bandwidth of 10 GB.
+
+[source,bash]
+----
+$start -a -f stl/imix.py -m 10gb
+----
+
+*Example*::
+
+Use this command to start a profile on ports 1 and 2, and multiply the bandwidth specified in the traffic profile by 100.
+
+[source,bash]
+----
+$start -port 1 2 -f stl/imix.py -m 100
+----
+
+
+===== stop
+
+* Operates on a set of ports
+* Changes the mode of the port(s) to "stopped"
+* Does not remove streams
+
+// IGNORE: this line helps rendering of next line
+
+*Example*::
+
+Use this command to stop the specified ports.
+
+[source,bash]
+----
+$stop --port 0
+
+----
+
+
+===== pause
+
+* Operates on a set of ports
+* Changes a working set of ports to "pause" (no traffic transmission) state.
+
+*Example*::
+
+[source,bash]
+----
+$pause --port 0
+
+----
+
+
+===== resume
+
+* Operates on a set of ports
+* Changes a working set of port(s) to "resume" state (transmitting traffic again).
+* All ports should be in "paused" status. If any of the ports is not paused, the command fails.
+
+// IGNORE: this line helps rendering of next line
+
+*Example*::
+
+[source,bash]
+----
+$resume --port 0
+
+----
+
+
+===== update
+
+Update the bandwidth multiplier for a set of ports.
+
+* All ports must be in "work" state. If any ports are not in "work" state, the command fails
+
+// IGNORE: this line helps rendering of next line
+
+*Example*::
+
+Multiplly traffic on all ports by a factor of 5.
+
+[source,bash]
+----
+>update -a -m 5
+----
+
+
+[NOTE]
+=====================================
+ We might add in the future the ability to disable/enable specific stream, load a new stream dynamically, and so on.
+=====================================
+
+// clarify note above
+
+===== TUI
+
+The textual user interface (TUI) displays constantly updated TRex statistics in a textual window.
+
+*Example*::
+
+[source,bash]
+----
+$tui
+----
+
+Enters a Stats mode and displays three types of TRex statistics:
+* Global/port stats/version/connected etc
+* Per port
+* Per port stream
+
+
+The followig keyboard commands operate in the TUI window: +
+ q - Quit the TUI window (get back to console) +
+ c - Clear all counters +
+ d, s, l - change display between dashboard (d), streams (s) and l (latency) info. +
+
+=== Benchmarks of 40G NICs
+
+link:trex_stateless_bench.html[TRex stateless benchmarks]
+
+=== Appendix
+
+==== Scapy packet examples
+
+[source,python]
+----
+
+# UDP header
+Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+
+# UDP over one vlan
+Ether()/Dot1Q(vlan=12)/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+
+# UDP QinQ
+Ether()/Dot1Q(vlan=12)/Dot1Q(vlan=12)/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+
+#TCP over IP over VLAN
+Ether()/Dot1Q(vlan=12)/IP(src="16.0.0.1",dst="48.0.0.1")/TCP(dport=12,sport=1025)
+
+# IPv6 over vlan
+Ether()/Dot1Q(vlan=12)/IPv6(src="::5")/TCP(dport=12,sport=1025)
+
+#Ipv6 over UDP over IP
+Ether()/IP()/UDP()/IPv6(src="::5")/TCP(dport=12,sport=1025)
+
+#DNS packet
+Ether()/IP()/UDP()/DNS()
+
+#HTTP packet
+Ether()/IP()/TCP()/"GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n"
+----
+
+
+==== HLT supported Arguments anchor:altapi-support[]
+
+include::build/hlt_args.asciidoc[]
+
+==== FD.IO open source project using TRex
+
+link:https://gerrit.fd.io/r/gitweb?p=csit.git;a=tree;f=resources/tools/t-rex[here]
+
+
+==== Using Stateless client via JSON-RPC
+
+For functions that do not require complex objects and can use JSON-serializable input/output, you can use Stateless API via JSON-RPC proxy server. +
+Thus, you can use Stateless TRex *from any language* supporting JSON-RPC.
+
+===== How to run TRex side:
+
+* Run the Stateless TRex server in one of 2 ways:
+
+** Either run TRex directly in shell:
++
+[source,bash]
+----
+sudo ./t-rex-64 -i
+----
+
+** Or run it via JSON-RPC command to trex_daemon_server:
++
+[source,python]
+----
+start_trex(trex_cmd_options, user, block_to_success = True, timeout = 40, stateless = True)
+----
+
+* Run the RPC "proxy" to stateless, here are also 2 ways:
+
+** run directly:
++
+[source,bash]
+----
+cd automation/trex_control_plane/stl/examples
+python rpc_proxy_server.py
+----
+
+** Send JSON-RPC command to master_daemon:
++
+[source,python]
+----
+if not master_daemon.is_stl_rpc_proxy_running():
+ master_daemon.start_stl_rpc_proxy()
+----
+
+Done :)
+
+Now you can send requests to the rpc_proxy_server and get results as array of 2 values:
+
+* If fail, result will be: [False, <traceback log with error>]
+* If success, result will be: [True, <return value of called function>]
+
+In same directory of rpc_proxy_server.py, there is python example of usage: using_rpc_proxy.py
+
+===== Native Stateless API functions:
+
+* acquire
+* connect
+* disconnect
+* get_stats
+* get_warnings
+* push_remote
+* reset
+* wait_on_traffic
+
+...can be called directly as server.push_remote(\'udp_traffic.pcap'). +
+If you need any other function of stateless client, you can either add it to rpc_proxy_server.py, or use this method: +
+server.*native_method*(<string of function name>, <args of the function>) +
+
+===== HLTAPI Methods can be called here as well:
+
+* connect
+* cleanup_session
+* interface_config
+* traffic_config
+* traffic_control
+* traffic_stats
+
+[NOTE]
+=====================================================================
+In case of names collision with native functions (such as connect), for HLTAPI, function will change to have "hlt_" prefix.
+=====================================================================
+
+===== Example of running from Java:
+
+[source,java]
+----
+package com.cisco.trex_example;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.HashMap;
+
+import com.googlecode.jsonrpc4j.JsonRpcHttpClient;
+
+public class TrexMain {
+
+ @SuppressWarnings("rawtypes")
+ public static Object verify(ArrayList response) {
+ if ((boolean) response.get(0)) {
+ return response.get(1);
+ }
+ System.out.println("Error: " + response.get(1));
+ System.exit(1);
+ return null;
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static void main(String[] args) throws Throwable {
+ try {
+ String trex_host = "csi-trex-11";
+ int rpc_proxy_port = 8095;
+ Map<String, Object> kwargs = new HashMap<>();
+ ArrayList<Integer> ports = new ArrayList<Integer>();
+ HashMap res_dict = new HashMap<>();
+ ArrayList res_list = new ArrayList();
+ JsonRpcHttpClient rpcConnection = new JsonRpcHttpClient(new URL("http://" + trex_host + ":" + rpc_proxy_port));
+
+ System.out.println("Initializing Native Client");
+ kwargs.put("server", trex_host);
+ kwargs.put("force", true);
+ verify(rpcConnection.invoke("native_proxy_init", kwargs, ArrayList.class));
+ kwargs.clear();
+
+ System.out.println("Connecting to TRex server");
+ verify(rpcConnection.invoke("connect", kwargs, ArrayList.class));
+
+ System.out.println("Resetting all ports");
+ verify(rpcConnection.invoke("reset", kwargs, ArrayList.class));
+
+ System.out.println("Getting ports info");
+ kwargs.put("func_name", "get_port_info"); // some "custom" function
+ res_list = (ArrayList) verify(rpcConnection.invoke("native_method", kwargs, ArrayList.class));
+ System.out.println("Ports info is: " + Arrays.toString(res_list.toArray()));
+ kwargs.clear();
+ for (int i = 0; i < res_list.size(); i++) {
+ Map port = (Map) res_list.get(i);
+ ports.add((int)port.get("index"));
+ }
+
+ System.out.println("Sending pcap to ports: " + Arrays.toString(ports.toArray()));
+ kwargs.put("pcap_filename", "stl/sample.pcap");
+ verify(rpcConnection.invoke("push_remote", kwargs, ArrayList.class));
+ kwargs.clear();
+ verify(rpcConnection.invoke("wait_on_traffic", kwargs, ArrayList.class));
+
+ System.out.println("Getting stats");
+ res_dict = (HashMap) verify(rpcConnection.invoke("get_stats", kwargs, ArrayList.class));
+ System.out.println("Stats: " + res_dict.toString());
+
+ System.out.println("Deleting Native Client instance");
+ verify(rpcConnection.invoke("native_proxy_del", kwargs, ArrayList.class));
+
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+}
+
+----
+
+
+
diff --git a/doc/trex_stateless_bench.asciidoc b/doc/trex_stateless_bench.asciidoc
new file mode 100755
index 00000000..2e0cbf3a
--- /dev/null
+++ b/doc/trex_stateless_bench.asciidoc
@@ -0,0 +1,242 @@
+TRex Stateless support
+======================
+:email: trex.tgen@gmail.com
+:quotes.++:
+:numbered:
+:web_server_url: https://trex-tgn.cisco.com/trex
+:local_web_server_url: csi-wiki-01:8181/trex
+:toclevels: 6
+:tabledef-default.subs: normal,callouts
+
+include::trex_ga.asciidoc[]
+
+// PDF version - image width variable
+ifdef::backend-docbook[]
+:p_width: 450
+endif::backend-docbook[]
+
+// HTML version - image width variable
+ifdef::backend-xhtml11[]
+:p_width: 800
+endif::backend-xhtml11[]
+
+
+== TRex stateless L2 benchmarks using XL710 40G NICs
+
+=== Setup details
+
+[cols="1,5"]
+|=================
+| Server: | UCSC-C240-M4SX
+| CPU: | 2 x Intel(R) Xeon(R) CPU E5-2667 v3 @ 3.20GHz
+| RAM: | 65536 @ 2133 MHz
+| NICs: | 2 x Intel Corporation Ethernet Controller XL710 for 40GbE QSFP+ (rev 01)
+| QSFP: | Cisco QSFP-H40G-AOC1M
+| OS: | Fedora 18
+| Switch: | Cisco Nexus 3172 Chassis, System version: 6.0(2)U5(2).
+| TRex: | v2.09 using 7 cores per dual interface.
+|=================
+
+=== Topology
+
+TRex port 1 &#8596; Switch port Eth1/50 (vlan 1005) &#8596; Switch port Eth1/52 (vlan 1005) &#8596; TRex port 2
+
+=== Results
+
+.Cached VM
+[cols="2,2^,2^,2^,2^,2^,2^,2^,3", options="header"]
+|=================
+| Packet size | Line Utilization (%) | Total L1 (Gb/s) | Total L2 (Gb/s) | CPU Util (%) | Total MPPS | BW per core (Gb/s) <1> | MPPS per core <2> | Multiplier
+| Imix | 100.04 | 80.03 | 76.03 | 2.7 | 25.03 | 89.74 | 28.07 | 100%
+| 1514 | 100.12 | 80.1 | 79.05 | 1.33 | 6.53 | 430.18 | 35.07 | 100%
+| 590 | 99.36 | 79.49 | 76.89 | 3.2 | 16.29 | 177.43 | 36.36 | 99.5%
+| 128 | 99.56 | 79.65 | 68.89 | 15.4 | 67.27 | 36.94 | 31.2 | 99.5%
+| 64 | 52.8 | 42.3 | 32.23 | 14.1 | 62.95 | 21.43 | 31.89 | 31.5mpps
+|=================
+
+.VM with 1 variable
+[cols="2,2^,2^,2^,2^,2^,2^,2^,3", options="header"]
+|=================
+| Packet size | Line Utilization (%) | Total L1 (Gb/s) | Total L2 (Gb/s) | CPU Util (%) | Total MPPS | BW per core (Gb/s) <1> | MPPS per core <2> | Multiplier
+| Imix | 100.04 | 80.03 | 76.03 | 12.6 | 25.03 | 45.37 | 14.19 | 100%
+| 1514 | 100.12 | 80.1 | 79.05 | 2.6 | 6.53 | 220.05 | 17.94 | 100%
+| 590 | 99.36 | 79.49 | 76.89 | 5.6 | 16.29 | 101.39 | 20.78 | 99.5%
+| 128 | 99.56 | 79.65 | 68.89 | 33.1 | 67.27 | 17.19 | 14.52 | 99.5%
+| 64 | 52.8 | 42.3 | 32.23 | 31.3 | 63.06 | 9.65 | 14.37 | 31.5mpps
+|=================
+
+<1> Extrapolated L1 bandwidth per 1 core @ 100% CPU utilization.
+<2> Extrapolated amount of MPPS per 1 core @ 100% CPU utilization.
+
+== Appendix
+
+=== Preparing setup and running the tests.
+
+==== Hardware preparations
+
+Order the UCS with HW described above.
+
+* There are several NICs with this chipset. +
+Bare Intel NICs don't work with Cisco QSFP+ optics, for such case you will need Silicom NICs.
+* Use NICs with 2x40G ports in each.
+* Put the NICs at different NUMAs (first on the left side, second on the right side).
+
+==== Software preparations
+
+* Install the OS (Bare metal Linux, *not* VM!)
+* Obtain the latest TRex package: wget https://trex-tgn.cisco.com/trex/release/latest
+* Untar the package: tar -xzf latest
+* Change dir to unzipped TRex
+* Create config file using command: sudo python dpdk_setup_ports.py -i
+** In case of Ubuntu 16 need python3
+** See paragraph link:trex_stateless_bench.html#_config_creation[config creation] for detailed step-by-step
+
+==== The tests
+
+* Run the TRex server: sudo ./t-rex-64 -i -c 7
+* In another shell run TRex console: trex-console
+** The console can be run from another computer with -s argument, --help for more info.
+** Other options for TRex client are automation or GUI
+* In the console, run "tui" command, and then send the traffic with commands like:
+** start -f stl/bench.py -m 50% --port 0 3 -t size=590,vm=var1
+** stop
+** clear
+** start -f stl/bench.py -m 30mpps --port 0 -t size=64,vm=cached
+** start -f stl/bench.py -m 100% -t size=1514,vm=random --force
+
+==== Config creation
+
+In our setup we will not use hyper-threading. +
+We will start with command: +
+sudo ./dpdk_setup_ports.py -i --no-ht +
+ +
+Printed table with interfaces info:
+
+[cols="4,6,9,19,33,9,10,10", options="header"]
+|=================
+^| ID ^| NUMA ^| PCI ^| MAC ^| Name ^| Driver ^| Linux IF ^| Active
+| 0 | 0 | 02:00.0 | 68:05:ca:32:15:b0 | Device 1583 | i40e | p1p1 |
+| 1 | 0 | 02:00.1 | 68:05:ca:32:15:b1 | Device 1583 | i40e | p1p2 |
+| 2 | 0 | 05:00.0 | 00:E0:ED:5D:82:D1 | Device 1583 | igb_uio | |
+| 3 | 0 | 05:00.1 | 00:E0:ED:5D:82:D2 | Device 1583 | igb_uio | |
+| 4 | 0 | 0a:00.0 | 04:62:73:5f:e8:a8 | I350 Gigabit Network Connection | igb | p4p1 | \*Active*
+| 5 | 0 | 0a:00.1 | 04:62:73:5f:e8:a9 | I350 Gigabit Network Connection | igb | p4p2 |
+| 6 | 1 | 84:00.0 | 68:05:CA:32:0C:38 | Device 1583 | igb_uio | |
+| 7 | 1 | 84:00.1 | 68:05:CA:32:0C:39 | Device 1583 | igb_uio | |
+|=================
+
+We will be asked to specify interfaces for TRex usage:
+
+==========================
+Please choose even number of interfaces either by ID or PCI or Linux IF (look at columns above). +
+Stateful will use order of interfaces: Client1 Server1 Client2 Server2 etc. for flows. +
+Stateless can be in any order. +
+Try to choose each pair of interfaces to be on same NUMA within the pair for performance. +
+Enter list of interfaces in line (for example: 1 3) : *2 3 6 7*
+==========================
+
+In our setup we have used 2, 3, 6, 7. +
+Next, we need to specify destination MAC addresses for given interfaces. +
+By default assumed loopback or L2 Switch with ports connection: 1^st^ port&#8596;2^nd^ port, 3^rd^ port&#8596;4^th^ port etc. +
+If you have router or L3 switch or some different connection, change the destination MACs accordingly. +
+In our case, ports are connected 2&#8596;7, 3&#8596;6. +
+We will give proper MACs as destination by clicking "y" and copy-paste MAC:
+
+==========================
+For interface 2, assuming loopback to it's dual interface 3. +
+Destination MAC is 00:E0:ED:5D:82:D2. Change it to MAC of DUT? (y/N).*y* +
+Please enter new destination MAC of interface 2: *68:05:CA:32:0C:39* +
+For interface 3, assuming loopback to it's dual interface 2. +
+Destination MAC is 00:E0:ED:5D:82:D1. Change it to MAC of DUT? (y/N).*y* +
+Please enter new destination MAC of interface 3: *68:05:CA:32:0C:38* +
+For interface 6, assuming loopback to it's dual interface 7. +
+Destination MAC is 68:05:CA:32:0C:39. Change it to MAC of DUT? (y/N).*y* +
+Please enter new destination MAC of interface 6: *00:E0:ED:5D:82:D2* +
+For interface 7, assuming loopback to it's dual interface 6. +
+Destination MAC is 68:05:CA:32:0C:38. Change it to MAC of DUT? (y/N).*y* +
+Please enter new destination MAC of interface 7: *00:E0:ED:5D:82:D1*
+==========================
+
+Finally, you can print generated config and save it to file:
+
+==========================
+Print preview of generated config? (Y/n) +
+++++
+<pre>### Config file generated by dpdk_setup_ports.py ###
+
+- port_limit: 4
+ version: 2
+ interfaces: ['05:00.0', '05:00.1', '84:00.0', '84:00.1']
+ port_info:
+ - dest_mac: [0x68, 0x05, 0xca, 0x32, 0x0c, 0x39]
+ src_mac: [0x00, 0xe0, 0xed, 0x5d, 0x82, 0xd1]
+ - dest_mac: [0x68, 0x05, 0xca, 0x32, 0x0c, 0x38]
+ src_mac: [0x00, 0xe0, 0xed, 0x5d, 0x82, 0xd2]
+
+ - dest_mac: [0x00, 0xe0, 0xed, 0x5d, 0x82, 0xd2]
+ src_mac: [0x68, 0x05, 0xca, 0x32, 0x0c, 0x38]
+ - dest_mac: [0x00, 0xe0, 0xed, 0x5d, 0x82, 0xd1]
+ src_mac: [0x68, 0x05, 0xca, 0x32, 0x0c, 0x39]
+
+ platform:
+ master_thread_id: 0
+ latency_thread_id: 15
+ dual_if:
+ - socket: 0
+ threads: [1,2,3,4,5,6,7] +
+
+ - socket: 1
+ threads: [8,9,10,11,12,13,14]
+
+</pre>
+++++
+Save the config to file? (Y/n) +
+Default filename is /etc/trex_cfg.yaml +
+Press ENTER to confirm or enter new file: +
+File /etc/trex_cfg.yaml already exist, overwrite? (y/N)*y* +
+Saved.
+==========================
+
+
+=== Some of screenshots of console with commands
+
+==== 64 bytes
+
+Utilization:
+
+image:images/64_util.png[title="64 bytes util",align="left",width={p_width}, link="images/64_util.png"]
+
+No drops:
+
+image:images/64_nodrop.png[title="64 bytes no drops",align="left",width={p_width}, link="images/64_nodrop.png"]
+
+==== 128 bytes
+
+Utilization:
+
+image:images/128_util.png[title="128 bytes util",align="left",width={p_width}, link="images/128_util.png"]
+
+No drops:
+
+image:images/128_nodrop.png[title="128 bytes no drops",align="left",width={p_width}, link="images/128_nodrop.png"]
+
+==== 590 bytes
+
+Utilization:
+
+image:images/590_util.png[title="128 bytes util",align="left",width={p_width}, link="images/590_util.png"]
+
+No drops:
+
+image:images/590_nodrop.png[title="590 bytes no drops",align="left",width={p_width}, link="images/590_nodrop.png"]
+
+==== 1514 bytes
+
+Utilization:
+
+image:images/1514_util.png[title="128 bytes util",align="left",width={p_width}, link="images/1514_util.png"]
+
+No drops:
+
+image:images/1514_nodrop.png[title="1514 bytes no drops",align="left",width={p_width}, link="images/1514_nodrop.png"]
+
diff --git a/doc/trex_toc.asciidoc b/doc/trex_toc.asciidoc
new file mode 100644
index 00000000..a41d707f
--- /dev/null
+++ b/doc/trex_toc.asciidoc
@@ -0,0 +1,331 @@
+
+ifdef::backend-xhtml11[]
+++++
+<div id="toc-section">
+ <div id="toctitle">
+ <img class="trex_logo" src="images\trex_logo_toc.png"/>
+ Table of Contents
+ </div>
+
+ <div id="toggle">
+ <img src="images\icons\toggle.png" title="click to toggle table of contents"/>
+ </div>
+
+
+ <div id="toc">
+ <div id="nav-tree">
+
+ </div>
+ </div>
+</div>
+
+
+
+ <!-- load the theme CSS file -->
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" rel="stylesheet"/>
+
+ <link href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" rel="stylesheet" />
+
+ <!-- include the jQuery library -->
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js">
+ </script>
+
+ <!-- include the jQuery UI library -->
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js">
+ </script>
+
+ <!-- include the minified jstree source -->
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js">
+ </script>
+
+ <style type="text/css">
+
+ #toc {
+ margin-bottom: 2.5em;
+ }
+
+ #toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+ }
+
+ @media screen {
+ body {
+ max-width: 50em; /* approximately 80 characters wide */
+ margin-left: 20em;
+ }
+
+ #toc {
+ position: fixed;
+ top: 51px;
+ left: 0;
+ bottom: 0;
+ width: 18em;
+ padding-bottom: 1.5em;
+ margin: 0;
+ overflow-x: auto !important;
+ overflow-y: auto !important;
+ border-right: solid 2px #cfcfcf;
+ background-color: #FAFAFA;
+ white-space: nowrap;
+ }
+
+ #toctitle {
+ font-size: 17px !important;
+ color: #4d4d4d !important;
+ margin-top: 0px;
+ height: 36px;
+ line-height: 36px;
+ background-color: #e4e2e2;
+ padding: 8px 0px 7px 45px;
+ white-space: nowrap;
+ left: 0px;
+ display: block;
+ position: fixed;
+ z-index: 100;
+ width: 245px;
+ top: 0px;
+ overflow: hidden;
+ }
+
+ #toc .toclevel1 {
+ margin-top: 0.5em;
+ }
+
+ #toc .toclevel2 {
+ margin-top: 0.25em;
+ display: list-item;
+ color: #aaaaaa;
+ }
+
+ }
+
+
+ /* Custom for Nave Tree */
+ #nav-tree{
+ margin-left: 10px !important;
+ }
+
+ #nav-tree ul > li {
+ color: #000 !important;
+ }
+
+ .jstree-wholerow.jstree-wholerow-clicked {
+ background-image: url('images/icons/selected_tab_bg.png');
+ background-repeat: repeat-x;
+ color: #fff !important;
+ text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
+ }
+
+ /* For side bar */
+ .ui-resizable-e{
+ height: 100%;
+ width: 4px !important;
+ position: fixed !important;
+ top: 0px !important;
+ cursor: e-resize !important;
+ background: url('images/splitbar.png') repeat scroll right center transparent !important;
+ }
+
+ .jstree-default .jstree-themeicon{
+ display: none !important;
+ }
+
+
+ .jstree-anchor {
+ font-size: 12px !important;
+ color: #91A501 !important;
+ }
+
+
+ .jstree-clicked{
+ color: green !important;
+ }
+
+
+ #toggle {
+ position: fixed;
+ top: 14px;
+ left: 10px;
+ z-index: 210;
+ width: 24px;
+ }
+
+ #toggle img {
+ opacity:0.3;
+ }
+
+ #toggle img:hover {
+ opacity:0.9;
+ }
+
+ .trex_logo{
+ top: 6px;
+ position: relative;
+ }
+
+
+ </style>
+
+
+
+<script>
+
+ $(document).ready(function(){
+ var isOpen = true;
+
+ // Initialize NavTree
+ initializeNavTree();
+ // Drag TOC left and right
+ initResizable();
+ // Toggle TOC whe clicking on the menu icon
+ toggleTOC();
+ // Handle Mobile - close TOC
+ checkMobile();
+
+ function initializeNavTree() {
+
+ // TOC tree options
+ var toc_tree = $('#nav-tree');
+
+ var toc_tree_options = {
+ 'core' : {
+ "animation" :false,
+ "themes" : { "stripes" : false },
+ 'data' : {
+ "url" : "./input_replace_me.json",
+ "dataType" : "json" // needed only if you do not supply JSON headers
+ }
+ }
+ ,
+ "plugins" : [ "wholerow" ]
+ };
+
+ $('#nav-tree').jstree(toc_tree_options) ;
+
+ toc_tree.on("changed.jstree", function (e, data) {
+ window.location.href = data.instance.get_selected(true)[0].original.link;
+ });
+ }
+
+ function initResizable() {
+ var toc = $("#toc");
+ var body = $("body");
+
+ // On resize
+ $("#toc").resizable({
+ resize: function(e, ui) {
+ resized();
+ },
+ handles: 'e'
+ });
+
+ // On zoom changed
+ $(window).resize(function() {
+ if(isOpen){
+ resized();
+ }
+ });
+
+
+ // Do it for the first time
+ var tocWidth = $(toc).outerWidth();
+ var windowHeight = $(window).height();
+ $(".ui-resizable-e").css({"right":$(window).width()-parseInt(tocWidth)+"px"});
+ $("#toctitle").css({"width":parseInt(tocWidth)-45+"px"});
+ $("#toc-section").css({"height":windowHeight + "px"});
+ $("#content-section").css({"height":windowHeight + "px"});
+
+ }
+
+ function resized(){
+ var body = $("body");
+ var tocWidth = $(toc).outerWidth();
+ var windowHeight = $(window).height();
+
+ body.css({"marginLeft":parseInt(tocWidth)+20+"px"});
+ $(".ui-resizable-e").css({"right":$(window).width()-parseInt(tocWidth)+"px"});
+ $("#toctitle").css({"width":parseInt(tocWidth)-45+"px"});
+ $("#toc-section").css({"height":windowHeight + "px"});
+ $("#content-section").css({"height":windowHeight + "px"});
+
+ }
+
+
+ function toggleTOC(){
+ $( "#toggle" ).click(function() {
+ if ( isOpen ) {
+ // Close it
+ closTOC();
+ } else {
+ // Open it
+ openTOC();
+ }
+ // Toggle status
+ isOpen = !isOpen;
+ });
+ }
+
+
+ // Close TOC by default if it is mobile
+ function checkMobile(){
+ if(isMobileDevice()){
+ closTOC();
+ $(".ui-resizable-e").hide();
+ }
+ }
+
+ // Check it it it is running on mobile device
+ function isMobileDevice() {
+ if(
+ navigator.userAgent.match(/Android/i) ||
+ navigator.userAgent.match(/BlackBerry/i) ||
+ navigator.userAgent.match(/iPhone|iPad|iPod/i) ||
+ navigator.userAgent.match(/Opera Mini/i) ||
+ navigator.userAgent.match(/IEMobile/i) ||
+ navigator.userAgent.match(/iPhone|iPad|iPod/i)
+ )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Close TOC
+ function closTOC(){
+ $("#toc").hide("slide", 500);
+ $("#toctitle").hide("slide", 500);
+ if(!isMobileDevice()){
+ $(".ui-resizable-e").hide("slide", 500);
+ }
+ // Show the show/hide button
+ $("#toggle").css("right", "-40px");
+ // Fil width
+ $("body").animate({"margin-left": "50px"}, 500);
+ }
+
+ // Open TOC
+ function openTOC(){
+ $("#toc").show("slide", 500);
+ $("#toctitle").show("slide", 500);
+ if(!isMobileDevice()){
+ $(".ui-resizable-e").show("slide", 500);
+ }
+ // Show the show/hide button
+ $("#toggle").css("right", "15px");
+ // Minimize page width
+ $("body").animate({"margin-left": $(toc).outerWidth()+20+"px"}, 500);
+ }
+
+ });
+
+</script>
+++++
+endif::backend-xhtml11[]
+
diff --git a/doc/trex_vm_manual-docinfo.html b/doc/trex_vm_manual-docinfo.html
new file mode 100644
index 00000000..6fb66a5e
--- /dev/null
+++ b/doc/trex_vm_manual-docinfo.html
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/doc/trex_vm_manual.asciidoc b/doc/trex_vm_manual.asciidoc
new file mode 100755
index 00000000..5c7021db
--- /dev/null
+++ b/doc/trex_vm_manual.asciidoc
@@ -0,0 +1,304 @@
+TRex Virtual Machine setup and basic usage
+===========================================
+:author: Dan Klein
+:email: <danklei@cisco.com>
+:revnumber: 2.0
+:quotes.++:
+:numbered:
+
+
+include::trex_ga.asciidoc[]
+
+
+== Introduction
+
+=== TRex traffic generator
+
+TRex traffic generator is a tool designed to benchmark platforms using realistic traffic.
+
+One of the tools through which TRex can be learned and tested is a virtual machine instance, fully simulating TRex without the need for any additional hardware.
+
+
+==== TRex Virtual Machine
+
+The TRex Virtual Machine is based on Oracle's Virtual Box freeware.
+
+It is designed to enable TRex newbies to explore this tool without any special resources.
+
+
+== Setup and Usage
+
+=== Setup
+
+In order to use TRex VM, there are several easy steps to follow:
+
+ . Download and install Oracle VM Virtual Box Manager https://www.virtualbox.org/wiki/Downloads[(VB download link)]. +
+ During installation you will be asked to allow the installation of system devices component interactions. Allow it.
+ . Download the latest TRex VM by http://trex-tgn.cisco.com/trex/T_Rex_162_VM_Fedora_21.ova[clicking on this link]. Notice that this is the
+ latest VM image, not the latest TRex version. This can be used for demonstration purposes. After installation, you can upgrade to latest
+ TRex image if needed (Instructions below).
+ . Open Oracle VM Virtual Box application installed at step 1.
+ . Under 'File' tab, select 'Import Appliance'. The following screen will apear:
+
+ifdef::backend-docbook[]
+image::images/vm_import.png[title="VM import screen",align="center",width=400, link="images/vm_import.png"]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+image::images/vm_import.png[title="VM import screen",align="center",width=900, link="images/vm_import.png"]
+endif::backend-xhtml11[]
+
+
+
+ . Browse and select the .ova file you have downloaded at step 2, and click 'continue'.
+ . Click 'Next, and then make sure that the 'Reinitialize the MAC address of all network cards' checkbox is **not selected**.
+ . Click 'import' and wait for the import process to finish.
+ **That's it! you're all good and set to go!**
+
+
+=== Launching and logging into the machine
+
+First, launch the virtual machine by selecting it in the VM's menu and hitting 'Start' button.
+
+ifdef::backend-docbook[]
+image::images/vm_selection_screen.png[title="TRex VM launching screen",align="center",width=400, link="images/vm_selection_screen.png"]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+image::images/vm_selection_screen.png[title="TRex VM launching screen",align="center",width=900, link="images/vm_selection_screen.png"]
+endif::backend-xhtml11[]
+
+
+
+
+[IMPORTANT]
+====
+You may encounter "VT-x is disabled" error, as shown in the image below. +
+In that case, please refer to https://www.virtualbox.org/ticket/4130[this link] and follow the provided steps to overcome this issue.
+====
+
+ifdef::backend-docbook[]
+image::images/trex_vm_bios_err.png[title="VT-x disabled possible error message",align="center",width=400, link="images/trex_vm_bios_err.png"]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+image::images/trex_vm_bios_err.png[title="VT-x disabled possible error message",align="center",width=900, link="images/trex_vm_bios_err.png"]
+endif::backend-xhtml11[]
+
+
+<<<<<
+
+Once the machine finished booting, login to it using the following credentials:
+
+ - Username: `trex`
+
+ - Password: `trex`
+
+ifdef::backend-docbook[]
+image::images/trex_vm_login.png[title="TRex VM login",align="center",width=400, link="images/trex_vm_login.png"]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+image::images/trex_vm_login.png[title="TRex VM login",align="center",width=900, link="images/trex_vm_login.png"]
+endif::backend-xhtml11[]
+
+
+TIP: Remote connection to the machine from anywhere in the hosting machine can be set up using the following command: +
+ `ssh -p 3022 trex@127.0.0.1`
+
+=== Running TRex traffic generator
+
+ 1. Change dir to latest version supplied using: `cd /home/trex/v1.62/`.
+
+ 2. Run your desired TRex command.
+
+IMPORTANT: When launching a TRex command, pay attention to make sure that you are using `sudo` prefix at the beggining of the command line. +
+
+For example, let's run TRex with DNS traffic. The command is:
+
+----
+[trex@localhost v1.62]$ sudo ./t-rex-64 -f cap2/dns.yaml -d 100 -m 1 --nc
+Starting TRex 1.62 please wait ...
+found configuration file at /etc/trex_cfg.yaml
+zmq publisher at: tcp://*:4500
+
+...
+<1>
+...
+
+-Per port stats table
+ ports | 0 | 1
+ -----------------------------------------------------------------------------------------
+ opackets | 17 | 17
+ obytes | 1241 | 1513
+ ipackets | 17 | 17
+ ibytes | 1513 | 1241
+ ierrors | 0 | 0
+ oerrors | 0 | 0
+ Tx Bw | 582.35 bps | 709.99 bps
+
+-Global stats enabled
+ Cpu Utilization : 0.8 % 0.0 Gb/core
+ Platform_factor : 1.0
+ Total-Tx : 1.29 Kbps
+ Total-Rx : 1.29 Kbps
+ Total-PPS : 1.99 pps
+ Total-CPS : 1.00 cps
+
+ Expected-PPS : 2.00 pps
+ Expected-CPS : 1.00 cps
+ Expected-BPS : 1.30 Kbps
+
+ Active-flows : 0 Clients : 511 Socket-util : 0.0001 %
+ Open-flows : 17 Servers : 255 Socket : 17 Socket/Clients : 0.0
+ drop-rate : 0.00 bps
+ current time : 18.7 sec
+ test duration : 81.3 sec
+----
+<1> Output trimmed.
+
+Now, lets review the generated packets as they are observed by our promiscuous interface (interface #2 in the picture at the bottom). +
+Notice that (depending on your virtual box CPU performance), tcpdump output might be delayed.
+
+----
+[trex@localhost ~]$ sudo tcpdump -i enp0s8
+tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
+listening on enp0s8, link-type EN10MB (Ethernet), capture size 262144 bytes
+09:38:53.953651 IP 16.0.0.2.1024 > 48.0.0.2.domain: 48 A? www.cisco.com. (31)
+09:38:53.963969 IP 48.0.0.2.domain > 16.0.0.2.1024: 48* 1/0/0 A 100.100.100.100 (47)
+09:38:54.960361 IP 16.0.0.3.1024 > 48.0.0.3.domain: 48 A? www.cisco.com. (31)
+09:38:54.970358 IP 48.0.0.3.domain > 16.0.0.3.1024: 48* 1/0/0 A 100.100.100.100 (47)
+09:38:55.967200 IP 16.0.0.4.1024 > 48.0.0.4.domain: 48 A? www.cisco.com. (31)
+09:38:55.977222 IP 48.0.0.4.domain > 16.0.0.4.1024: 48* 1/0/0 A 100.100.100.100 (47)
+09:38:56.975355 IP 16.0.0.5.1024 > 48.0.0.5.domain: 48 A? www.cisco.com. (31)
+09:38:56.985379 IP 48.0.0.5.domain > 16.0.0.5.1024: 48* 1/0/0 A 100.100.100.100 (47)
+09:38:57.981659 IP 16.0.0.6.1024 > 48.0.0.6.domain: 48 A? www.cisco.com. (31)
+09:38:57.992358 IP 48.0.0.6.domain > 16.0.0.6.1024: 48* 1/0/0 A 100.100.100.100 (47)
+09:38:58.990979 IP 16.0.0.7.1024 > 48.0.0.7.domain: 48 A? www.cisco.com. (31)
+09:38:59.000952 IP 48.0.0.7.domain > 16.0.0.7.1024: 48* 1/0/0 A 100.100.100.100 (47)
+09:39:00.009403 IP 16.0.0.8.1024 > 48.0.0.8.domain: 48 A? www.cisco.com. (31)
+09:39:00.019456 IP 48.0.0.8.domain > 16.0.0.8.1024: 48* 1/0/0 A 100.100.100.100 (47)
+09:39:01.015810 IP 16.0.0.9.1024 > 48.0.0.9.domain: 48 A? www.cisco.com. (31)
+----
+
+
+Let's have a look at another example. +
+We want to generate simple http traffic. The command will look like:
+
+----
+[trex@localhost v1.62]$ sudo ./t-rex-64 -f cap2/http_simple.yaml -d 100 -l 1000 -m 1 --nc
+Starting TRex 1.62 please wait ...
+found configuration file at /etc/trex_cfg.yaml
+zmq publisher at: tcp://*:4500
+
+...
+<1>
+...
+
+-Per port stats table
+ ports | 0 | 1
+ -----------------------------------------------------------------------------------------
+ opackets | 40983 | 41946
+ obytes | 2563951 | 6015664
+ ipackets | 41946 | 40983
+ ibytes | 6015664 | 2563951
+ ierrors | 0 | 0
+ oerrors | 0 | 0
+ Tx Bw | 520.83 Kbps | 1.27 Mbps
+
+-Global stats enabled
+ Cpu Utilization : 3.1 % 0.1 Gb/core
+ Platform_factor : 1.0
+ Total-Tx : 1.79 Mbps
+ Total-Rx : 1.79 Mbps
+ Total-PPS : 2.11 Kpps
+ Total-CPS : 2.84 cps
+
+ Expected-PPS : 102.71 pps
+ Expected-CPS : 2.78 cps
+ Expected-BPS : 764.51 Kbps
+
+ Active-flows : 0 Clients : 255 Socket-util : 0.0000 %
+ Open-flows : 107 Servers : 65535 Socket : 0 Socket/Clients : 0.0
+ drop-rate : 0.00 bps
+ current time : 39.6 sec
+ test duration : 60.4 sec
+
+-Latency stats enabled
+ Cpu Utilization : 1.0 %
+ if| tx_ok , rx_ok , rx ,error, average , max , Jitter , max window
+ | , , check, , latency(usec),latency (usec) ,(usec) ,
+ ----------------------------------------------------------------------------------------
+ 0 | 39490, 39489, 0, 0, 1276 , 106714, 91 | 1737 1880
+ 1 | 39490, 39490, 0, 0, 226 , 107619, 203 | 1694 1041
+
+----
+
+<1> Output trimmed.
+
+[NOTE]
+See http://trex-tgn.cisco.com/trex/doc/trex_book.pdf[TRex full manual] for a complete understading of the tool features and options.
+
+=== Updating TRex
+
+See http://trex-tgn.cisco.com/trex/doc/trex_manual.html#_obtaining_the_trex_package[Related manual] section
+
+=== TRex Live monitoring
+
+Once we have TRex up and running, we can monitor its performance using TRexViewer application (Supported only on Windows OS).
+
+
+This can be done by following these steps:
+
+1. Download the latest version of TrexViewer application and install it using http://trex-tgn.cisco.com/trex/client_gui/setup.exe[this link].
+
+
+2. Start the application and fill in the following: +
+ - Trex ip: `127.0.0.1:4500`
+
+3. Click the play button.
+
+ifdef::backend-docbook[]
+image::images/trex_motinor_config.png[title="TRex viewer start screen",align="center",width=400,link="images/trex_motinor_config.png"]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+image::images/trex_motinor_config.png[title="TRex viewer start screen",align="center",width=900,link="images/trex_motinor_config.png"]
+endif::backend-xhtml11[]
+
+**That's it!** +
+ Now the live data from TRex will be displayed on the screen.
+
+ifdef::backend-docbook[]
+image::images/trex_motinor_view.png[title="TRex viewer monitor screen",align="center",width=400,link="images/trex_motinor_view.png"]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+image::images/trex_motinor_view.png[title="TRex viewer monitor screen",align="center",width=900,link="images/trex_motinor_view.png"]
+endif::backend-xhtml11[]
+
+
+[NOTE]
+Make sure TRex is running, otherwise data will not be available at TRexViewer.
+
+=== Architecture and network design
+
+Since no hardware is used, TRex simulates traffic using a virtual internal network, named 'trex_intnet'.
+
+The following figure describes the virtual "wiring" of the virtual machine to support TRex traffic simulation.
+
+ifdef::backend-docbook[]
+image::images/T-Rex_vm.png[title="TRex virtual connectivity",align="center",width=400, link="images/T-Rex_vm.png"]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+image::images/T-Rex_vm.png[title="TRex virtual connectivity",align="center",width=900, link="images/T-Rex_vm.png"]
+endif::backend-xhtml11[]
+
+
+The VM runs TRex with single client and single server port. The traffic generated by each of those ports is switched over the 'trex_intnet' virtual network and received by the other side.
+
+TRex identifies only the packets which were dedicately sent by one of those traffic ports and receives them on the other port. Hence, packets generated by client port will be received by the server port and vice versa.
+
+Network adapter #4 can be used for capturing all traffic generated by both of TRex's ports.
+
diff --git a/doc/visio_drawings/illustrations_stateless.vsd b/doc/visio_drawings/illustrations_stateless.vsd
new file mode 100755
index 00000000..9a979a7f
--- /dev/null
+++ b/doc/visio_drawings/illustrations_stateless.vsd
Binary files differ
diff --git a/doc/visio_drawings/stl_streams_example.vsd b/doc/visio_drawings/stl_streams_example.vsd
new file mode 100644
index 00000000..423781b8
--- /dev/null
+++ b/doc/visio_drawings/stl_streams_example.vsd
Binary files differ
diff --git a/doc/visio_drawings/streams.vsd b/doc/visio_drawings/streams.vsd
new file mode 100644
index 00000000..dd925c1d
--- /dev/null
+++ b/doc/visio_drawings/streams.vsd
Binary files differ
diff --git a/doc/visio_drawings/trex_2.0_stateless.png b/doc/visio_drawings/trex_2.0_stateless.png
new file mode 100755
index 00000000..01787f99
--- /dev/null
+++ b/doc/visio_drawings/trex_2.0_stateless.png
Binary files differ
diff --git a/doc/visio_drawings/trex_2.0_stateless.vsd b/doc/visio_drawings/trex_2.0_stateless.vsd
new file mode 100755
index 00000000..cfebc367
--- /dev/null
+++ b/doc/visio_drawings/trex_2.0_stateless.vsd
Binary files differ
diff --git a/doc/vm_doc.asciidoc b/doc/vm_doc.asciidoc
new file mode 100755
index 00000000..05017a9c
--- /dev/null
+++ b/doc/vm_doc.asciidoc
@@ -0,0 +1,4 @@
+
+moved to server spec
+
+
diff --git a/doc/waf b/doc/waf
new file mode 100755
index 00000000..4e68fedc
--- /dev/null
+++ b/doc/waf
Binary files differ
diff --git a/doc/waf-1.9.3 b/doc/waf-1.9.3
new file mode 100755
index 00000000..7ad6ae70
--- /dev/null
+++ b/doc/waf-1.9.3
@@ -0,0 +1,170 @@
+#!/usr/bin/env python
+# encoding: ISO8859-1
+# Thomas Nagy, 2005-2016
+#
+"""
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+"""
+
+import os, sys, inspect
+
+VERSION="1.9.3"
+REVISION="826456a3e8d1d27787c240c6ba69d280"
+GIT="b022313c197614245fae732c0dd1d8167b9ee5dd"
+INSTALL=''
+C1='#)'
+C2='#%'
+C3='#$'
+cwd = os.getcwd()
+join = os.path.join
+
+
+WAF='waf'
+def b(x):
+ return x
+if sys.hexversion>0x300000f:
+ WAF='waf3'
+ def b(x):
+ return x.encode()
+
+def err(m):
+ print(('\033[91mError: %s\033[0m' % m))
+ sys.exit(1)
+
+def unpack_wafdir(dir, src):
+ f = open(src,'rb')
+ c = 'corrupt archive (%d)'
+ while 1:
+ line = f.readline()
+ if not line: err('run waf-light from a folder containing waflib')
+ if line == b('#==>\n'):
+ txt = f.readline()
+ if not txt: err(c % 1)
+ if f.readline() != b('#<==\n'): err(c % 2)
+ break
+ if not txt: err(c % 3)
+ txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')).replace(b(C3), b('\x00'))
+
+ import shutil, tarfile
+ try: shutil.rmtree(dir)
+ except OSError: pass
+ try:
+ for x in ('Tools', 'extras'):
+ os.makedirs(join(dir, 'waflib', x))
+ except OSError:
+ err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir)
+
+ os.chdir(dir)
+ tmp = 't.bz2'
+ t = open(tmp,'wb')
+ try: t.write(txt)
+ finally: t.close()
+
+ try:
+ t = tarfile.open(tmp)
+ except:
+ try:
+ os.system('bunzip2 t.bz2')
+ t = tarfile.open('t')
+ tmp = 't'
+ except:
+ os.chdir(cwd)
+ try: shutil.rmtree(dir)
+ except OSError: pass
+ err("Waf cannot be unpacked, check that bzip2 support is present")
+
+ try:
+ for x in t: t.extract(x)
+ finally:
+ t.close()
+
+ for x in ('Tools', 'extras'):
+ os.chmod(join('waflib',x), 493)
+
+ if sys.hexversion<0x300000f:
+ sys.path = [join(dir, 'waflib')] + sys.path
+ import fixpy2
+ fixpy2.fixdir(dir)
+
+ os.remove(tmp)
+ os.chdir(cwd)
+
+ try: dir = unicode(dir, 'mbcs')
+ except: pass
+ try:
+ from ctypes import windll
+ windll.kernel32.SetFileAttributesW(dir, 2)
+ except:
+ pass
+
+def test(dir):
+ try:
+ os.stat(join(dir, 'waflib'))
+ return os.path.abspath(dir)
+ except OSError:
+ pass
+
+def find_lib():
+ src = os.path.abspath(inspect.getfile(inspect.getmodule(err)))
+ base, name = os.path.split(src)
+
+ #devs use $WAFDIR
+ w=test(os.environ.get('WAFDIR', ''))
+ if w: return w
+
+ #waf-light
+ if name.endswith('waf-light'):
+ w = test(base)
+ if w: return w
+ err('waf-light requires waflib -> export WAFDIR=/folder')
+
+ dirname = '%s-%s-%s' % (WAF, VERSION, REVISION)
+ for i in (INSTALL,'/usr','/usr/local','/opt'):
+ w = test(i + '/lib/' + dirname)
+ if w: return w
+
+ #waf-local
+ dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname)
+ w = test(dir)
+ if w: return w
+
+ #unpack
+ unpack_wafdir(dir, src)
+ return dir
+
+wafdir = find_lib()
+sys.path.insert(0, wafdir)
+
+if __name__ == '__main__':
+
+ from waflib import Scripting
+ Scripting.waf_entry_point(cwd, VERSION, wafdir)
+
+#==>
+#BZh91AY&SY^:Z})2ÿÿ±#$Âÿÿÿÿÿÿÿÿÿÿÿ]á õ#$8E„xaöÜ÷½¾Ï8€#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$¯}W#%÷;©™‘U¶Ò*[·]ö}÷i«n»¶ú8¥9ŠÓ}öwË:,×¾ä懻vÕÜûÞìÊåï«ï½žžöíží‡må… h­»»Í‘&°t ö^î=;>í{í¢_CO}<¸ÛÝÙ›ï>n8>¯[Ÿ]=ãT$ìß{ß}óï†ÎÞ7¾Ñ×ß{íyéÀ÷`ïw7w>»ì#$#$@#$Ÿf€ô£§#$m÷²€uàæÝ·p#$õÞÒͧCÐöòíkf©­Ðjû½×#C{y zØBöîÛ`7³p …D¥Dª=ì{e’B%t(H•Q@÷p:Rß{¥ç¶6±Æœû«=i{…e»QÛÛxÔvÊ¢•¶îu×וèûç½^#$Ùçœë«Íõ»ìhÝâz={0ªM½k˜õÕîî{ëdäåžÝÓ}:vßq÷²ÝÝ^×ßo·×ÞîÏ.‹m}ìa°îz:U­Ølì蹺I»»Ü÷·yêÆ:ëBîÑÝ•†ÚÙ’DE»½ÞÓƒÖ j¨-;`)èy¡{“¥éæ·¶ô[ÝÝtjT}¸;ëÓ统më >€ÑC­m÷Þv+뺷 lÀ »ëm€ß]xö‚•íÊà-÷Ýï{¼¹ÐPûÞö¼çÆîÎY]4Tû½ÞMw7Kì¹Ùèy3mºãÝß]õçVÕˆ©»·vÖ2ÙÖïmímÍíÝwtÜç·{ÑÞóW'‘ÎíéuÜ¡k®w ‹í©>ŸlwgÄ÷m³Õæ#%÷¶¹§kŸyº{Г*ðªÇϱ÷cÞͶï½ÓÝ}îíµçg>òöì”ûÜ÷¶û²œ^öTæÛ–v­Ýi¼µ€Òw¼ïAööÁ÷yä9Àz‚Š®±Ðj©ØSCs;´1‘îw¬î¶÷*Ü4è=Ærw{3Ó]W©º®Qpj{qïe#ºòØ4 ÝîÛt·\ï#$on: #$×½×¼îõµÞ=×î¤ãÓíïfÉ뻎÷Ÿ{Ýh¹Ñ·#%Ö ›Ó]±GÍ„’×ÜRz­Y–ûÝ:}q]ô;Û/-÷Ýsî÷{›O€’ :=æ·weí«“1^Ï/Ro`´s#AŸmÈû›îÝ“f¯;«­¸ÙÔÇÝöï:½–ìÝÛ·É®ÚÉî%ìÇjë&d F¡ZzÞÇ©ëß{ß[Íè5í‡1<|°åïmÞ̓½Ãn×Rؼ#$À»c]8ª£žöô·{CÖ½nèàîÙÓ/'¼â¯}7ÛÝõ½½Î¯¸í×¼ÉuéÖmòì=ïmŸg ®Ÿ@%Û(PíÌÝ«ÜðPã®ðÞ#%6Áçvï\¼÷ƒ¯@]Ÿ@„‹¶Ì†»€#$äqäÕµõ5âÝÀ=±JT(-»¦Âö.@C»=ãw“³ZÇ#)Ï0é7wnvs»9\Ú’H¹vî›d›­ÍïïLÄgS=«).Ó+“Û;Æ=Vû¸|C<ÛíÈk¯£àclÝ::>Œvfê°È–uÒûk;_v÷£4ë˾û©_mƒ»»q¯WƒÞ;ÀѾ5ãœ4Ñh#$€#$&1‚i€™¦™£TýS5Ê#$A¦mCÓj‚S@„ @M ‰&™&4“Ó)©æ¡š“Òz™<¡è&‡¤#$#$#$#$#$#$H‰¢h ¦M?LT÷‘SõO)¼©êyOSGê†hh#$ h#$#$#$$õJ(MM5jmOSÒz!ê@M#$#%#$Ä#$#$#$#$#$#$$ˆÐh#$ õ<4ÄÅ<˜ÐIê=M4Ó@¨Ñ #$#$ 5#$04ÈM©O5)ùLjbŸªfžMQê~¤=‰COP#$#$h#$#$õßæUZüe ý+Q«cN¿…U§e6C>ª­w³Œ†Ø‘X‹Š*$Š#)Ÿ#$ ‚–Š€¾¡0@Š~ƒóÏƵün‹†°Íhüûz³s_ŠO8§§"âf¥T¼'…/1WXÆ#‡ÉüøÌ“´ ZD@ÐPÙJ É70¦E„P†¬92/>Mšcg£#)"îêUŠ‰‰¦²’®fñ‡Å¨ˆš»ÄMÚ—£ˆ©À“#$ÆP¿w/úG:&„#$+iš6™Ý]U¥j±­´–Õ±­±j£jÕíV–Ûk–$!Ë¢À6‰›Â(†0Qlˆ@Ä@H@õÅh€€ª$F@dAPDÈWl2DÆfÆ™šY2!ˆÍ&™¨ˆš‘,dE”£J)¶“aŠ™’h%5MFØÐa¤°S"4M˜±Œ–™Ej5,hLYShÒE&Éh­IK-)M¨€`›- YA0e±hÔ–Á-¥4È&¤d !E4©CJlmVš¶šÚ¤)•C6$ј™!4DV–´f–*JML•-°MšÌš–¦ZK&&IQFÀ†‘²¶B"ÉE2(Ñ"ED†¢”Ö) Ñ°Á ŠCLÆiQjRŒ4DŒÊ0MC"2ICd­$„RÄ#i(d HH†’šVhɉ£aˆ¦RTX ¨aR*d‚,jR˜I‘É M dÄÅIF‘-šRM&$‹DÊjcf@ج–± ,1RHdÄ)±¬šiX`X$˜¨Ø *$ °š ‘(Ñ“JX ‚a(c$¤ YŒ™„Y52¢#P›%D“!5&ÀHD’RV @A‹,Ì6Œi¢`‚e‰")Fl% 3l³YKeŒd,i¦hĦÅ%’6(•!3 Œe, ©f@±%ˆÒ¤–™AF“4ŠŠ¦ˆš¨F ”%‘ˆÙ)2&‚i™Q£0£YH ÆÁ°D2dÂfPR1 š’„Å#$l“*fkLcl¦Ó$!™©ˆR ÖRÓ#)É„’$¤’Å“fÈÚfb&dŒ”²&ͦ#%±")™(lÉ¥2BÆb̦ˆ©D”Y©d¤Ê) #&$È¥dÑdŒSe  E+)$Ä’e5&Æ‘#%#%#@„cBIY¤Ãh4lf2I„²e"2ÄK6JdRˆ„´„Õ6lZ+Bd’’$-E°Z ›FE# la Â2Š’*,¢Q‚´¤ÌQ¬f†„™#)J)”±FDJaŠYcL°"Q”e!¢jÔÛV‰$É¢Œ)‘¢ŠI™­ÉlJY£LRde3K*Y£¦hØ[$¢š"±”Œ#%!M-~Ûk£!²´„„©De±¶6ŠŒTl™2ËÒM,´FÂ6I¨ÚÈŒ-2b6S*HÖDS Í3Y5b$”ÖJBÑ‚”IbTi…ƒIŠZS&LÙ6 U¦6PŠÙR*•JÌ)³c1”µ±cdF¶M2²%Ifmd«-”¥4Ãk"…2#b´fÒÄ–’™M±mƒk cZ‰*#)6Ú%Tm6M´M!T`¨,U‹bÃ6l&Ù0¢*¤)A(¤ECR‰¦ÔÚ#lT‰XŤ,›i$ÛVËm¦CbÂBe2¦¬šfÈÄ4´Š)"ªšÒ¨Å2ÓK3i¬Ò›TÓ‹R¡”I6ÒÍRÈ¢ˆ[BKfL’˦Y5¥©d-f˜ˆ ˆeF’2Å01 H† Ð˜ÀËQjIQ†R¨¬“M&M%€,R)fˆ¢¤–FD1”I#)”l¦hÐH’š#%‹2B"–š’ȶ4Í4"i!€ŠŒ˜ÃL$d´X! !&ÁBlQ¢M“4³µ2³¢“a2¤¢£bÅ•A)‹3I%”(¤1fmÍ£c‹hF‚ɳB’ÑCHTd2#F2š$¢–RЙ6Œ ²‹$–!ѵFšÑš#)†Š–Y6ci3idÚ6Æ#!’@˜È,’XJ’£4Š”Ó £-’ScPm˜lÒm¤¢(ÈiFM¦V³”ÓS4‘ P"DA*RŒ hÛ41F€k4›%1 LD¤¤„¢ÑªQ¨Ôh£lFÆe°Òa¤’… $‹E(‚6(°&ÐVYdÙ) Ø´d,”³If´l$k¨“E –Z‚¢Á’ØØ(ðÆ6ÊPÖ‹A¥)–B£D‘TÈÔDe6ÖELmŒ˜ &ˆ¦e S)ID•,J"Kjƒj#),”Y*5S3E²RV6µ)ŠJ6Sl†²X´4K6d• 4˜¤£$F#)É€Ôd™Ù“)²R›3bb)TU•“Y"3I5£)ªKbÙI4Y QI&V¥”Õ)ª$Ôj¢¬e1i5² Q¬j(±H¥3#)dfDÆ•"(6fÌÖˆ±¶MÑ©*i­¡•b¨Ô…#%h¦k4ÛE£QcV2kRde(²³h•£‹2ÆÔZT°¦ÙFXÔĤƒeFÅ•KclYš“¤ÚÅ&ÙLÍQ£hÃH¨¤¢­¶[m4²&XY„‰41ÒhÑeI6¤ %X­Ø´Í[F5¬ÚMše­ˆ²[SSl…µm¢Q”P26’cÃYS5l²*(ÔI‰$ÊI‘$5“Z,ÍTÇù?Îü—ùÍüç5€ñ÷ëíÿ1+J´4}Ç ·—ýL”“ üpÂ(Ѥ¿–¹¤²ú¯|×óž«×7ó›×«zÄT´ÇþreŠÀ¢hó%qÿ†µÄ#ƒ#) GÈ•, ’H‘0(£#w»KD¸äß‹1ìÒÿÏí­¿ðH’…+r¡+JK ÕÏV^=EŒM‡¹vt3´Õt­˜Hc¶&Û¬-q(ÅË®Ï#)1údop Œj2q!aSM•Ê×DûêäG—dï; _-ñâï‡>µzܳ®¬…ߪêní®MëqóÚæ*ùWËÑ\ÛÑssM¡´$ÐÆÄj×gx(Æ0.¢%ˆ½Û ¾W6Fo[šJ c*è-5­X\r¿õì³üèJH¥¡½ÓÕ[0YB u@©çRÛ*€±}ônð‡T¦\mâب¦¦Ð¤R›ä¬k™"˜Ò»Õ$¶#%Ñ1ˆaöi¦`´5æÎGÝí…h Â#% 2Ãvü ðà¶~†#i†Ë:óí‰/üîÖ0…•¨v.â©ŒøõåáÎt]ÆÍÌ’QlX±Q~9}³E  ʨŠO]Ql÷3ŘVnÒ@)¥Á¡FG8ê‚>ª\‡3k†÷Ö\#)MS.‰mAF#i)&Km±ª4Š4dƒ{œlË ÔÁŸb¬9bÜZ¨¥a7"rpaÆŒ“®éG9¾[Ëοտ¹¼¯*1ií×l}%s¥ßC¯ªo0W좑:5ýN4Ç?ØóÀLð D¯ï¢™³ZbÖ#)€Ž*C#$È JÕ £h§ô`׶~|AÖ 1ýz‡sÒ4¶ÅµCòÉçÚ¯S¿»?Ã˽[iq`m•ù,,¸žWTEÊ5R›n%:¼S“#%†ïãfã¥m¥CXÌu¡ZR#)¯§?ø¼«°³ä›VÜ(äß¾¡[PP±Â0BÂ2'DÓ3n ±j?ºÎ‡§hf$ØM”}h¶åXÿª‹dê˜JJe¡Ýe,#%éÒñôvCÕ¾"[~¼å0’Gá–¡ÆFÐÙŽKñKÑÃË{5Ŷ…ÕEkFÿ­ë£,R,_Ô2Ld—ãë¬Y>/ÓÕäF=Òy¿ c¦Dw¤ßýg÷‘O';Ex”Ö#ub±–õb$ÅqO<Jìiv¦ŠE4Qxæ’Æñ\¹¤YýŸJÀŃàÔF(W±±ŒØ÷~ú™¨(-2„AXW··€ ¤CDI±IóÝs_umtéËrü~u^Kí_sáz±êáƒEËtÛbóÎýôe(ØÖMŸ7rÄO´aFEöT¨²EE|jªJ™­nÅy‹‹&¾Ção¨,–üÎÅÕAhî½F[îÍ ŸÞÔº…$¦˜ú¨[fÇóÔ9ä Â#]+k6CÉ­ê™Uôï×y¹[³ dÚû» åó`ÜiNa+€ÄÐÜdÜEhú±²(–” ´Â˜('m@8ëJn†^®ß%ÊT—Um*íÝV)økÏ!—~ú·w’wvÝÅI<®ÔÙ†¨Ze¤‚0§Xôq«¸y`[&Œ™i.šÂYy¹J©ÛE½”)Ã…Ëb¨‚§>Ú“Í1(Ü ©äû[ò ¡êãˆøFðxŇ¹Ž«)¶åßÌÔ;a¨þóŸFx±¾©áŠ®¤8¿Vq'^ب½­_o—•b©))…#J_šF ýøíLCPqŽœÿªÎ×ßtÑõûhˆhß#)èÃþw²¸3:”… ¤GÅ S“Rߥ}}{­Ýj5(®ˆmìã繊ELbfNw¦Þ|%$¹ÆäFî¨G_½–ÃE‘1½ê RÖ¦·˜ÒÝúndM4ˆópÓò> 0U2#)B­t«$Î$‚TL¢‚E„yêj·¯¹Y€Ù4Ã>ˬ×akÃâ]^üÄÊX綱Œ¿ ˤúò¢VŒóÅÈZ¡=#%˜É0Í^ãÖÈ_•)0ÄCz“ ,>§u@¯×ñ$nÅèÊ£ªL†sœzgnú£êÓ½45ê>—f|=ý6Ó•ºë¢´f©2—$À‡éUܨ¶åTüšL/ÉÉPî¯i&AÕ-)ž5XJN{նМR»• JXŠæîú_üþÜš@C…wÝ3û8Â3ª^ç9õçÉ—"œpã>Ñ[øÉ„=ìë"ÓädMǶf(öȃ^|oH0ïø´Wd1Š’#%¹õöå1¦Å4è=Fj/n{ˆŸ’GÝ—ëµÍ¶%ïÉb½îχ$™Yð«ãÎýé8§~tñÁH"F†'ù«j„ZÖe¼ƒVnœÌBBéùH5$Ï… 4ÑÏrðÏ#)«te¾m ¦ÎUƒ)çu<äíü\Sía®ÓÙïÎ^?«ÒùävBI$Šƒ‰wqÇ] ,P‚S$ÈO~´]¤ä½ê)@Àí1´‚Qƒ}ÚÐQ±uËApX)â.<Ü ^£ƒîñ‰!1ÛàìwÓ±H ¬&€ö7²ÌÔ™ºt­Á"Õš9fŸ'‹nC‰±õ‘8ÐÇŽ-“èü!ø?¯^çxnY̨ö‚Ó»qô“ç.XìãÉ8ÿc¿Õ¿nÿñ¼êuß{ÖŒYTNŒ X§ -L´(¤Rûî!sw½Ôü=u5A'“BÇÛ—æеTµEzUAL¡ ©~|¿Ãyõ{Öö>?·ºó’WÚÔÞ©õ0¤X£eIÝEZ(øPRUê…÷³ÐOÍùók>j×*kV¤F~¶S—ï}ùãôb÷n–Iù"ÛWÙ:n¹ºŽgT¬õ{mr00#%}ß–†{âÝüµWW~¯f#%­fƒY1„ûrÖïPÓ3óÒSþ3°÷iFK*‘A‘èÐŽµ'ÚC#% áÒÑŸ„ÅSSŸ3ƒi4qüÕp3?Œ‘ñleWÞAV;”¿Œ‰æµîÐi ð҇碑B`vë›DQc` Å"ÒhŒê_v¯Ÿ)ù74c皧ٿvp> > *ƒ/u† 1ÆdƒmwŠ1üFvNç®#)oÑvÊcËíšzxõÜtsã±Ä6”$aÁÁif©>‡óD˲Xü]¡2”ô»üž»ïg!ÆJƒu|/¦a”Ë%{q÷™É‘òd¾ú¤x3[…=Û\ÄJÖì‹X>i5;+HÌÄES#)'_ÂP[oZªCÁ6ÈJGïo,r‡ôqÓn!­és9õ»À‘]ˆUTÏË‹ñlÁÍÕ:ãlà ‚W¥ž.!û¯+¶]Ânwhˆóˆ£›#ŸF¨"(˜w³àÂìvôÇNu¦œ¬þíhòì¢#)h]ÚD´ñaK–RŠÄ:3„aaÏ]{|w–Û!\kbb·$„‡ýŠüø¡Ó@]h”!7¤ø'ö9eu1ÉÓ"?žÿéggœá_&Í#)ª(£”´û¤5D<ö,ØI P0Ää‚“¥š:îtTŒ’B-)pàÖ"Ñ­‡cÐOÿQÚôŸÛwsÇ1„bäÎyÖ>5°º?Îáf1ÞY°„ßI[Q[9ˆâ©ˆF òüq÷èrÁBj¯ªîÕõ64âïáÍoUäi b§uú¾}Þnšj¾e­Ï…“?uOÀt ­«ÏÌÀ\Š#=ïzß#)²Áxá‘Té ’BØA‹Çá/.&«s¤fÏÃéÙ1^˜ iwdršòä¬+—onàZ•¼Ê¤㑘)#fõcêÖ¦ àD 2ƒZªHrd™üžrä¥ç]*ªÜuè³´ÃiLŽ7–¼žûdzÂbÑZâÝŽü4úSo"ø!þžÐÆ|¢+‡C÷òâZ« ³?”æ¦;ÌÈ…—{%ø‡'õqWÝÁÃn4A•@¢õÞk4 ¹›9ñ¡E†tͨ·8½ž^®V`{u­ŒU4UnvÔËoÍAŠ"<±ìÁ–~ÿݦØþüQ>Ïë¸,í~Ç Ãù±e‰Êb­â"(3Oéׇ‡N{vçҋó¦»÷dð(¼šÔ¥•TqïÅ“à:€®•\æuð¶ø=|.XC(¸{<m¸!•PÈýT—•óŒàuÆœˆ•XÔ±DÆÔ3Êi±Žëª·Y‘“Ž’‘= §g}Œ|ªª˜ú¡ŸÏTËÑlÕû÷âII•æcðG,Ž‚Û9"}3ð`qcÜQñ“| «LOÒ|Ö=ñ_#†È+2F¹–—ßâ«€Ù7úÊ\]s—Ãì¿-}wå|[ŽÕÕ¸îáÊ?NË®UVzX8Úñtøð³5µœBÙ–z3õ³ÑÎg|O++àî”Ö ¸Úä¶A(ÖI7š5éQ…Íûáµ6ÎÎ5àä‘{zÕ›¼n‰Zïs#)¦µþ:û°yQÚÌ‘Q‹Ÿàé›{ª¢Rêè¬)\]œ¨ød9¹?7MKÁ“M@È•àØœ™û»kfjxëE¿T.õ¿Û{øê[i¦K­`QèAt‹‘ÅîVÚ­B—Ïç‘êXû^~ï~Ï)Û×ÈF\†¼¦JýÑžñÛGYeA,·èšߎÁ-5V%ý5}#C@¿Ru‰p݈—ý) ¸J¿*–ìê#,žPi®ÔŒgë‘þ®#9˜1ï—3)˜õéf#%6•T-_wK EQEž¤ú8 娾ì…yú"½²ßÖÀ¬[ìi7FJ(ÙSôû*LxÑÜìþ|ñKXueØRwg¨vñQfâ.¾j ‚ ãM±sX²O|#)x#$E³[ˆdÇÃySÊïPŸwg^Û²5ÎÉ|Ó¡ÄÚÃœ¿íñÆlm £H˜rBiªêIŒ3Gž^|sÏQï¾G˜m,oD>Z‡“#Y-O˜Ñ?S‹ízï…÷Œè…ŒmUQ9$¿^,d/W¥Ó ÇF¢e¡g½„ nϾNÕÚÜAnèýFÅTý±-ë \íg·.ž!±2Îaú {µ¬ÂØÅ»ƒ—󲼋H÷à£7ê½;ï¨Õ# º»¯…”Ã@Öš»¤YÑ©uÝBQù¬}˜Û׆fTH4˜[òo N?Lµ&° TTM*`½)àÔ‰ÍHŽ#%*uf3‹D—uK­P2‘š’…;­Ñ‰<÷ö¼áWÅñ‚ꔬ©«ž<ÝÛ›Äír)qÕw']a}¤"ªÅ–´Än–ÿGÃÂÏPäËÙ»w2 t•P¥‡gCOaRI;âë"òœöþË•ÑCÒfpþö2l¾§ð?ph#$šsñÚhÓÜ6mË¡r…Ê´uÿ·Ý/ã]îQÁNÅÌ”ú²•ôðáiŸéÖNoxÇë3¯n•x†QSÆPªo½–ë ¢ÞÜÅIV÷TGo(Ê”Æɳ{òk»[aÞwuBC5˜<®±k³}£Nؔƫ7sæ¬ÞêfšJ\ÙBOÔìýz5ÇW#%É#%‘ÝõqK­f:;˜_ =ìû+­ ÊºzÇÛ&ÛºýðÏng³øè䢓J)›Žßù#cý¬¦à}`Ö1|qª›¼2Ý}ŠTÈÝØ#B5ÀP^TÿMNÆõï¡·PÐÆ1ÙT  ZÞ>2ÈÐ þÇÈý›ýùæÿ„0,å ‚Ñ¯OÓ-ùgŒ¨v.>]Ô»Ë+¸Ù©QtB¼Ý¦;+‹žÅyig•;žó~‡ÿ¬Y)¸”gÆwª¸Îÿ\ ÜÎ¥u|ž¾Ì„šv³´‡É÷½¡ªÈ÷}Ó;XìÖîJj9wmìpû~.ڻ㠙¤N“¾wÔ÷x<§;'Î&wN—| Izç#%ùv[ê…E‘[Ç(–JÞÑ#•97µP8dæ•Èj"ºÖÿâ¾™–q¥Ã›~Üb§·$‘ô[@ÀoÏ0Û[hI†Úªø¦å¥ÔŸvãâcE`|ð?¢„œŒž!½¾~&:4†ŠqÚ¾.4L§b½Œ3·º÷ÆlJÁI­ÈN¢ÿãTgßåÍ9i–Ÿ>nI7Šèò›»¼»¢.8“mSZ–ï´Cˆ|ü|~°Ñ‰±È°Õeê¨Ãèh¹Ð4•Ó“ÙØK7(]…nêF!§ßżèÚC!¬¸'|%Ž3Ú6[+ŒaF¦©CÞø ¥Æ\¦ÛO‹\m‰”D¬Ýdg¦š,@™Å^@ÁØ × XkZqÂØÝ79v”¤^õ#$#È@ Qä^ jž½êŠ%©²¥ãm.ºÕž³e¸¾Ýu´Wƒ r¨@Gr´—ŠDŒØin¸_¨f!b®Ü[fÜÙ²RqÊå°\#•‚åa¶¨Ž'ªôßwWÈÏ;ôð®|øt³7åKýÐ'€´^ßÃ×°Þ¶“³¦qÖ–ðJío,×±[”Êí. =µógpaýH­}>!×ó±1ÅG“é-ÿ.üñÌÛU5žM˜Ûïî¾#)|ð$RFÂ/þš:¼²°LsH!üCo:“C™‡D†îOõù7jŸ%Ĺ²L`ÔÄkm(0@§DÑ@c0éo±â‚wÇ¿2òFnž°=\j×ÎØÎÒûqø±œ/]_O¦Û+çì™ÒS˜ÿ€XZíb•åGÞäpA=ºŽ¯¤5¸J8ù•gˆ…áø—o>öë‰W›Ç~{vÆ|Îؘ|}XÞé›9N¨C?W=yjÈËEwˆ-ƒ€±$6¿Ik¯jôn) ?bÇ*dªp;ÇX^îòÉ[ǤÒ'jˆD·x=Ñ­ª*,|iž?L$HyļQXþ/·)t;s¹¨ùc7ãÇ”¬Á¢Jiä8C@ÛNlŠ~G‘\ZnJmG5Vê]ά‹©“#$¥¾fƒN†²½yÔbç 9'Á¯"Q¹Êýa`o¹Rª†â!-LÁÄ|‘T¶ñ´D;ŸDYßëZË;™Á¥¥î·»#)#$–‘·z&iÃíÓë»—f]¤f4 R”þÎwzzÿÆnQ¡³íÿ6íßÆòçB&ôÌ/;•ì?PÈcÌ–¨ÍR‡z¢òÉ Lªö‚7Í»ówü¸íñ#$Mwþ@ÙìK‡ÍHï÷ D @HƒÐKüáOG 6)Æ0]¾Iç¢iJ‹$ˆŠB´ŠÇ]¬0óp4GÀϚšÉ;n-Ê|ù»üÿ-#“š±¡#$?‰Q#%[Õz<Ü𢟳6vã3`u`ƒR¨%â0§`gkžÓöät#$&Uš†È„‰D( #$'Ëû«ÝöT+£RÚéÒçG¨êÓ(HzƧ`>(`óÓÜÚe#$7ú|güRpFäŽcÄy èRuCöÍ—0ÿ¯» †w*µÕåD̽žuD2#)ŠAù*†ÀÉ&~íêé1[™p’»I´ˆ€òsF¤Ž§ßƲj³Ñ¯¢w|‘jG®m!)±„gοw×Íi(Œ2óøhêN>ñÎvq­ Á8XAEçÙÉèbG—Ç_‡ k’0K}´ªñúÃPˆ­`‘Š#)ž—1!ç@ŸÅ9À"&~X<@Sàä…“Ïé·Õ*c*&ûþ0û`€v€Á¤&Bmv>íÂíôwçõrÃJÃÛ^Õ2Åaðžhk_Ãú§íùÓ Òµþ’àØ6ì×?¦X>á24",Œ‘Ï}¤r$nZ9hNz?Lî›+e÷ég¯ÁâÝ”×xþ«øwØjS@¹™aª”ªç^EÈC6QŸåk]߀Ŭælôhå}¹g§MSøÇëáf²2|ü5?…‰Óùy\á(=cŠo.z˜:ë©1g›ëûõ¯Íïyiœ=›ð`>#%9å•Èe5­~¨úº¶¯"ˆ@ñŠ'àaŠBÉ’Ðì€ãêÑK¦$´! @`£‹”±ˆ|C‡ûWeȽED=nª©ýKnŠ{Ù(Á´É%š¸yŠ²7|IàÇ÷qþC9UWÌ<µ N×VM…ï6ÅÉQ$QU@›yhŒéʺ¡¿º‡fžÊ½ä‡å½’&ÊëϵŠ6ØŒž<˜à¿lûœá™¼“J°ŒéôZþ#ÏÞþìiq¦´-8ûǬrÝ“[c|JÉ*ÚILw]ê¡#ô}#?ÑÇMu†¤‘µwžç´Q {d]=K±þ¯ë¹hQl""^ûìŒa'ëïãîW3 Ÿ/w«3"ðªAGHQ:Üþ=˘Iéïy'É0&½i³¸påm­`zl6}b©Œý³Æ,-˜}t÷y]¤_õaôÕðèÐÕ†#)g…â~dÿ•¦Ã¨úBbb/˜ÚØ ¤­Ï›µé·ó¼žäi°Œ4öçëÁ½˜GyÈ@o³ÑÇ«„0­¡‡û²AMObô(ñm9N.Ö5Niݬçsc‡ïÌ“—úo[´ôúœÂ½ÌÏ¿—@~÷LJ&hŽ”Ñ3òÓ;³Ì#)JK6åô]ô°£7›²¨y_nP[L§ Ã0ÏXI#%æ°(“ÊTŽ‚ò#$KšwV~byþýú__>ò·”ÿ„<(Ù ¥¢y¢™ [ˈïÅÝ;´Ã`D!õŸ§ßuy&?;¼y›sŠoz`×ñ)Ô°;²ïrÃI}x—²ð¯uñ;ÿ^ù#%#%®š¥U4Ñ­#u-QF±•OX}ãñÞ–xí)ä0ëÊqZŠ÷û–˜A;â#PßC"S …o|d‹c±¼´ÞY$j±©4mÓPä¡Eù¾¯sp¾ÅqMYaÄìÙÌ;ÞÇŽÑüšÚ‡ºD’n;{ûnSÀ‘Ê;Õv’…¸ï l­ÇM#°ëù—Æ<}€zh5…ðþ¨q›Jõ;[I¬Cc§|}x‡UFütãé¦íé~Ÿ9#)9]Á´™„ Ï·_T¼‹…c§ñ¾Ü+kèmi¥¾n@±ÙÉÒ‚LU°íî¸õ¬CÔgüqÎ&öw¨vçz5ˆêd!¤MÉœp°•¾~#9ç#)"hÈö )¨Íãhqd.å1!˜·RÆÙÃ|ZÈ*ÄCW—¹ñ¼½#Þ¤Åo}žžg#%(c“þÑÆ®gœÏµÔhwØ¿â– L¸ÇeÎlEw‰*1"("*ÊM™ô7ƸޱØb²#)lÛãüá#$cTÃÙГ^ÝÔ vx§RÇýÄs‘V*-æp#%*Àºìa7£Ê!¥^Æl¯*Q0 "Ô4Ø}Ÿ¿Sê=ú×ÃàR³Ü÷ê¼Mõ×ß} éEO £µ¨!Äsü+ªyÐAû–µhˆéY¨Ò’yv|ŽÚÝÂþŸ–ĘÙϳ‚:ø ‡c¥›u]ˆe7g}&Õ¸…î^¬vÑœ_®"#%œýÖºs#%Êι}Ùi‘©¯ã½ƒh^ßÂìjmu¤PP;ÅGY¬‰—Ш ¡ö²Œ™cXV¾J’(‹0V“‹-ÎRprÁY²²&j³F²*)™5$.ÜÌëwéd2óÈX㊅Bå|ŸÂ8=Ö ³N®Î‘÷^æ-tu ŒâÛÊ5Š#%¸ég³Ã¾p˜|#ƒNF"ç/P”ÃòÖ±(z¬¸Õ>:¾—#)Ÿ•ð‰Ëøë±ìùÎÇZõ¾ŒnÏ7!#ˆÇ.ŽŒ;•±·£G;ksc³änžž~çöÁÝ-ºâm2Mä½Ý\*OLU—6ú²‹qÅa¦¨ˆòê †v²#$Ê#%š$À uxê"’ÕužòŸàCè–}ó9©Ï¹àÏCû¯ãKM½„.ÿ*ÒÕ}¿cÓ{9ö(÷åù’îAþh5³Ý}IŒœqalá|QduD+661Q\WWwž.מ9ˆ±ÍÑi’’ "‚Ú;_—¦uÓQ½Ÿ†õž¼ŸvpøéÌãðy!d ¤¦EU#%…"²ÌUa˜ cQ:Ɔ-zá‹oØTÈÆ cŒŒ0Hl±NÄ2p°jîŒØ§§>YÛm*vmše©U7`³JoÍJ}*28ô”RrIû¦tXìv/j¨£î—`ܪ#e§f†hMXþRIB⃱‡0,®Pã{W”t#%Ö77m—”Ýß©²îÇ(uôåêXubM„`NÍkû¥ –@¦È‹“’€`V™)¼ôå¤ÑmÇ1 ðaÝ!aHŸ#ÊãϵÆLëm_ ²>aŒšEoõI½ªquÛöˆý}',»3†y_ÑdîÞyÈÓµs½ôÖÌ™¯>ße«8~±…ZFçD·`¡<}4DqKXÞ§÷jbhÐãA¬ÃRbeç}"hC’æë6Ç[1KC”›Šb¦¡H ¥äe8ÆìU@SFäÃÃ3G|ì×C´.Ó7_gžµê¼[•+žÑ þ xÌ#$CU¡T«R4X^ØlT£ x”`aBÇ—£œw÷ýo¢?M¯]ùó Hl’R±H¢6… /QjûÊóç­¹¬S"ŒT©¨«à›nhÛzÔ[è©çzÑ“%,HŒFØ£U†6Ä@‚°ˆ²+–ÊÎû«.·›#nwØ-³ÛÑÙ´ÇEÆ>³{§aûŸfÏŒsF·^ËìÎ}71ÄŠŠûVon‰—á×î¯gœõÙ½KõzfmÁÜè}c¶iPÁ;EÜùû“ó£UÚ“^º@ÒáúEŽxÐ=Ú-„#%+Û· ‡ë·©¢ü”‰:»—%˜Èfùf<]åæ¶ãVC»I:~ü,Èû°+>ò¦Õ芘s=¶¶ƒ Ë–f62±WS+DVFÆ”–ƒrA»k&#%}+ž_¦%Ãk&܉‘¾Ì‘®ÕF4TàÚÆûr-nøßžÞÉÙ@>­SôV¸ÆÅéA³ê8z-Åj l!³ù`3XøíãË”±õ¾«ŒçàûáÎÄJ¦_sÞª˜ÂtÔËÉ8ÙïµÔŒajO#%@Ô™¶¥„ÎÏIü,ç#—úú¼tÛ#%ý²ïç£÷_À_¯CYžó) AÄ×GKh¸Ù¦’•ÌP"é“ŒgðÓÝ-Ƶ ¶×iDzÕA¦æƒ Ð^'v7‘³æ¹1‡c'¦ þ!Î?¯L<1ºmË1ç³ÏWëW)ñ²²Öˆö6¨Œ#$Å<ÑöšØbR"¢h³º@k,± nu¡\ÁéÅ*¥r%RRkŠMßÙW §Íâ¥Ø7>×Úòø^”*â÷Y°Á(&B"¼ó<9«"+ ç+ÍÌA¢¦”Ò0Y% ‹24¥!¡8°‹|:÷ryvëoŸMQ»ly7°Û#%<âA7ŠÀ±œ2A¢„Ò¨o.¸…Mh©4iX,4·AšM¦hyš £MF¦¬(iã0Ñ ÄØ!ˆbÓK³#%ý{Îú '„DbšCx2¹Ô°Pâ²V9£ñQIŸn5U念ƾòé‰\£Hñ9¢]§—ÉøMƒ¢ÍfîîŒï å#j¹Ë}zÄ®0äN¤JQ0.ˆò¸á§#)f§ð#Æ©”cø}¯T̆ìw‰ÜL†ëd²Ù#%\×+6 6+²êÍflöfþÝü¡ƒf; M;Ã&òcÑÊo9Q¯àn@°mN'<à ÷wçפùâÍ"Ê#%_SF3Z«¤Ž­§ÂÿmËÁÓ %&DüªªSPÉMسšÞ)61‡ÊDÔÛø}æ#)6^ÒéSäÃ,lûEíë«5Çìñ“ñgÊq­ß2¥Aüí+/÷;k¿\~&Ã1¼m5ÉÉâ3‹³eäÿÍŸ«· 2c@˜4ó&ÃAN5“ÞàØÍ› Oð·rg¸?Zùuf/œçw#$ý„kª’m3¨ÊBvRRkµÒêQR®%!©íõ^RôÙöoα¶éÈÄ㓦4±Æ²¥$@-ís‰~#æ»­½Ë€>îÍx3›µ–(Â&†’èÍ·.L«˜Óca5"2i¿OI_\*·÷‹˜q}/l°Ñ#)¨Dë‚sÙˆ7ôk·Ÿ ÏR%O>FÂU=Ø£DüqïÀ*l?óæ#%¢ r/y®vïø¹ß÷r=¶*±‰ýUm´ˆªT2«>ՆبKñÌåœÑK«¡`Iµ®­\Žh!ÕÚ÷-!°çS&Hô ºX€¢%FÜ«\©"×6æ¨Öæ’ Á#% $Cç*LDŒ1ƒ²Ù¼» A w ó¢D˜0‰C%ŸÍš“§ç3kP q 'O¼.R†¯ ^ŸÂÇì;¦ÙˆÔ:=AIë=g¤&^`ûP€žÿ_QðUŒ3–ƒ°ï̼9Wxð-¶ßFà…òTâ¾·®Ÿ[W¶äã@Ì+Ò¥¯¨pÉ9j 1œÌ+èöéýÚGä4õîÿfÞ^„lTbƒç)YO,ÏTǤëÙ7 —|5y?-·ûµŒ¶Æ‡?žçr?C>€fú'°`À«eŒ@k(ã|‰ÁT>÷ŒLþY….?²­æ3ð?Ã^jþ[Æ[]¥)WbR#)²¦VÔ'è¤L¥Â't¶t¾¸wÖ­»·ç#%—JÀ¤rè^’ê ÙôC‡GÃ`È$[…°ö#%; îꦙ% ÛªéåáeŸ};9y_ô뮎nÌ>z#$×ã^hk>50ïø¶êÖŸ_Û«ÑUZî®#%o‡<XDa„F³×¡tÖ1&.HGk$‘å<›jyø.RxšY`ý(²¸ëô|׈#)Rj e™sHsRKŠ0 ³@Æ9‡þh‹ÆAõ{>ünú¿œ×·Ô`ÓöIAÅa\óÏj¯%â–Û³Š¶£a–6Ý°¶#ù?³¯ê#$Ú(æ#$KÚïãjÂ5&ŸWëü½¹ø€&zê$I#_±Ë]ßλÁöi[=‰Õ£_0QÀD`G”¦×r~‰“Ûb,*[Ÿµ ŠfÔ–OÄ®dÄl©bQ~‡‰£MŠ¿¤_mÚŠ0Áª”SDB¢ZHñ÷;b[Zþ€ý&ËwúÍÛ0öÿ1Ô?À"ôÙç#%¦ÚžVÐœ tì•"»#$þÄ,L ³î¾¶hÅlX¢”U@ÐA¨>AjHvÕå¤'g»ã_#%ߎ'ª{e`¢Ê%£AÉãþ*”’‡Ï§ßýKÌí¬#”J8äblÁH)ø¥0?Üa$¦ïp7ùéMh”Í2 »À¦rdZbÔ›^M¸†Ûʶ¾¬ª¼š#$b`ªª¨ˆ’´aùfãür}é‡Òí©WU®“)Œ"#%´¡Ø¤ ñ_à>Èé•þ¥mpQ¨+™/oîrWKCðµ`ùFY”þýX±|°=gö´º˜`ë ‚ f˜fJ®“ïÇúç«ì4…Ú³Q3ò¯Ð¾ÔÊ礞;Îãq´„ñTr…@JE\`¤)³Qå]¡¸€È.²wGUbw: Ý¥‚Ðr!&˜_Q?µÃCAêñӗι<_‚>(œ¨Pˆ# ì¹4Þ°È¢¡Q,;x…#ô—P=|î˜5_¤ÃðhÌöýìYC (ôÚ¡ù˜~-¤7vtªÂB‰ýU&‚ b$þ¦ÐøïÓüû¹h ýVRßì‡ñ#½qÝæý“lýÞߌütþß‹¿¤cçŸX>ï“Þ ÿ|9]äÜŽ…Ü *8yòÞ3F¿Ü>šö²C%^ ôð<Žú—7Ž0 ;ˆùcIý§?¼`‰šSH±ªÉpÞaº—}²W‡ßWG#$.œ[…CÊ.ȃ]‹ƒ­oÍ_²‰Ó8O}Áˆàdó5¯·*׿÷AFøéåãY­+BÇ]Gãö‰å_Ó»~ý‹ë+þ=Ý‘Ù[i’wåéýrPi¯{…9˜ovθ$l§tFq¸›J©Üsªz¾;.H~ª¢ø1¦ wP]·©{Ô1Å”¿³­,>*4ÖßÓ #%‡-à@zô£‚½Ê÷bè6Z‚HRÞ­úNˆ»'9Ürw¯šºÆ–çqðp.Q£t™-¿ê3!Ö…!USܯ Ex4ËŒ]°ˆ•”ùˆýiXœHú@òœ†€÷ë{ÊnG#)ßB0T ïg#$\…ãƒj?Cg¡ã¨P2šD0*¥ëœð˜dÅÊ…àH*å,ê1Ð ‚“«;Ä…¥2˜it.0TV7E3'þÝÈœËU½¬©#$à„¿~ùv¤9±wÓëï®#ì±£ó8ÙöîÓõ@ý–u$}Kiðd ‰8)\GíêQñÓ@s”ÜÃœVA„7-Ä—"ÐB¼¨$ ÒGòÅF5|û*û&伄¿¬„$PÖIq.Î#ÍÙ‹jF• ú]ðgû?ÏüÕlÚ&;Àuùè{±ëLabýkÒëßGuÒ„ItV+?;´išh€Å ÂCc뙧¯Í ôÈu5´XA"µqÖsÊE€¬köÞÀU(&òÀ1#)Jó« pˆt± 4Ö<¯aüî&Ñ›²òIÕ#$VP”#)ü•<Ê.ÍËWTó«•¼i×X’¹pK®r;møÒƒ÷¢!T›ä.#$-?„…Ggˆ(,Ö¼ác#)K@¡’˜©·¢a"ˤ Þ)#$ˆæWÛ•eŽ(ÏCžˆQÎDAB2ÝÌ(‡k3.9ôÛü¹©ÕÖçý]óy>‹<~Ž]xr@ó õOßÇ5?>‘ó~ÊižýõxÛöÕï…”ùòÈ.x²ê¤gð¤h)mU×~3éoWˆsLIÝ‹èéüviÝn›ZÈãn\ÿd:ñìÓîžývMåyaå»nl$¢‹*{~ŸÏ„0ËQo!òêëá/ë×t2ªgSÃ~¼Þ9ÜšÝvÙtx«N—òÈSsŸòݺ_%ß³W†>SH¬}ׇ s/.Û>hÜàÙYp[…@MÝ>zßO-¸ù1²c«Ž^;­ÁãËË™(ýÉéþTzû¤ØB£Žsô|®Â#):³»›–üÙ¥F³U¼GÐôÛÇÒñÁMR¢9©ãÌäï¦.×W"ÝÍGNÙ6~L: ëÿÛ²w¹:gŸÊ鶵Œ¬®ðüto›ƒ¹þ¯§MNßÍzYËü¥QvSÍðpÊ%Ñß›>0¶—Ð2Ž‡þÜ€Ôu#?”Rî¸ÎeÚ,ålc—A”])l·~9- ×_mT袺ú…V¨ºêèaMõKMTÐ#:–#%™QŒf=ÁEbÇ<Q–±¹„\®ÔàÐy‘sÊ®j>¿C“/UXæ¡vøïÛnš{w×ݧW”èÐMr»O¹þQêô룯E·uÎŽMí†ÍYšÊrÓUoæXÈmß:òòÕ.^líI€ãßΧt•ˆ‘™ü7*¿ÜêŒuûó3ÆâF[åÈýQèù:ÅŽº9/¯ïx×ó„Î<¾>~UêûÍßÄ{ƒ ±ßlèˆù!¸êÎ1ˆ»«L*öÂЪù«¿#)oúqòf¶¦ëÈSG‹«Šº¥ðY˜|Ϙ`~½rè½™p¯ýCQ«ì•¢/wöýuë›MöÇž(—õ»Ô9°¤ý´÷ëªêqýTDŠhN6¯»àÙlÓîÿËùfÀz®Ž³w§ù{q‰>Z³h0Êûht ˜WrÍ´×/ÃÔÛòFÏÑñ8P3Ý\3w¬7{8v¯%ëaÅ À©'X!y-îý¾F´Q›­Ëè©ž=»ÚìÍüpiúøÈFš$.WõòúÙßÒk“€+û#)ï÷iÀÿ·ŸoߎIH·‹"¡Gu¢Ø{/¶\šç®uü^Ÿç:~}c“}öþ'ßòü¿S~÷æìËMVòC#$á7aéóÑ»Ç3}ÿ˜!’¡WSx5-ååîaëü?©‘>øÐØ’×¢‰TtvQWOâ>°µÃ{÷H¤»ægr@¨0¾!ú¾/c@È}o(>T‰Q@¢£ BZoe_¿@_Üóæèêç^ÜßG§m›yÏÇæöy;9ñèx,ͧîç6á,ó~s­>®wí`D¨£‘¯Ï›GÃ+?oÒi!sbÿ©zu9yéaúìä^Š9¿,Û…¿?G zGà6ŽaáÃÉÜ?xP·jº>#$;ïÏ¥#$QúŸÊä“ú‡hö~什ùÿoá3Çá+œ1¹56ºý´ …7‘' ÿßk…Nªøò-cÓ¿w°ù?M9'°~9„Ç_êññ fP>üÿ'Ví{@ø‡Ýô©::÷0EÞ¬ð£ÞW¡ì8)ùÈfh$54€ü¨B ¾ˆ#);^º:i#%B$ÂAPoæœu¼^2±ôôÿ¾n±´[«‡ÉúHñÛ/ab¿cpv#$÷×ÕÅsr;÷Qºš ’ûÏeÏÉB(÷‚;¿_Êê¢&H;“¢ø–ü×yhÙòé[º8#ó¿f#Cé[œOÓŒÄÖY#$(ÇaPœd%„Õ#ê`Â5e.CŸr’fH&Ú\Mw y+¸9© °T ñJ$s•#)Õ½uWœò_·<gLkˆoõØ`ìqÊ®[©ÝhÜeÔ¥Hˆç`Àg}:£pƒÔŽ}ß·t’º¨ša¾—š¶.Ç\E¢^š I,1Ç(Ö!œ „> «îÛŸW}¿·¤&¡ôêû…¾½ÝYã: ˜ër£S¶W=% TÊŽW¹ðœÃõÑ$¥G²‡lÑÜ8Ãm‘“k—ÕŽË;Þù½Ík/0ŒáówdÊâ´oay##)ê£)ËÇ÷æ¦{ÄtŽ‰è±ÒŽ!‚¹óË%ûÚEïisÂ<¢á‘¯;éK2yÐówz• DBIÑU^г«P$ý^ŠÌu¤ªÍ#%1ÊáEó¯#$Ú2A†Z»5šæ1÷].×pËËu=o½¢o<{ë·¦8þZüGbòí¤5úûþ ?$z‡"+Kˆ…Ä®‡Š í¢ ŽÕ%‰˜#b,7ù÷gå²#$‚´a量q¶ý§×LÍÜ¢iêÅã·FUB#%ÕT颔à#)}ìö}<Þõ9Ä*<÷Ç‘-‡Ã7K® _‚(çÏœ#)nÑ«ŽzzŒlž™ÿg[Ñv·/ÃëiN8t»~̪—E.‰äÄ™3?¨°=rØÍ®ÿ+âÙ½Ÿ6àãì¶h仳ÄimKå¼\Ç´g?‡›Kiaàw»Íü5®g¼¯ã¿ÐÏ÷ÝðÀj³…»<öøÆ5ôÖ¦IBitàÿeè}®ëƒ%XêÂ/u5:ºÝÇïtéô]l»?<Ô <âðÝ€(Ò5–写Ž$’_¾áv“øyæ*¯åü•%<s ˆíón»#$êDÉ*1ï—ËçÌŠL€§Œ4ÖØ#%%ñÐå7våóeù~Ÿ8#X#ÌÉó£ÜÅJŠÇÊç {ÞÎr–VÜ„¬g³,qz¤_™ã[.ê1í­Ñ†¶±’Â8‚= ©EJ$ݱ!±Ã"ÂAUZPq¸TEŽš•BÅfŽîSFe™ªŽ#)˜*KhfLvÁ¤Øi’hÀd,‰¡¡º¤ŽÆƒMIc+ŽF1Àvéš4ÒJTD0))'φq8&¦dÔfˆHÛì‹B{qZ8dÚu¡ýß²ø[Ñã!xµœ¡AAóýÜÆy,?ˆ—”b—ñþ¡­G%¨½tr§D,;Œ,"Œm&;Ž˜xrE+ðøgOoóÇÑdÈ#psuÇ…¤ËGGJf³v…¤Þ ÆA±aR4š„!¬÷â Òm7&²2¨þ¥@% IšN?²ôöË]žü}×W.Ñ>œ¬çû-莃eŒüøÝ;1ŠE\+QÊj«6hW*0åXnÓK#%ߤã³0üú¼·ˆö"®Ï¯ö÷aŽAùÝ»n¤t=5#%'7ãœYtFl]&®tüÕ˜ÅÎóõ,©ª“‘º©ÛæñÇ?êüÔ=ó”auRhô‰$v»æ.ïµ*Xíäó~ï½}òñ͟Ø¢V„y#)ýnç#$2#)4ª×õm`+¬çøq¿ê…[vrsã[—iʹNΧ{‘ÅÎs=ÊêÕ†¼½VÃøôvǺ?_çšGlƒº¿½pOlöÌóùø|_df_O7÷×Ë×É.ºþ´N‹jþ}™¼ô˜!âü#8°:ýåö«Šb~ž°vM'!Û ü¾Pg¿V„2biºÑäjÑ"¶”ÁÊØ¥;䧥‚£Z!¡”}íæ¼^èóÏ9·Œk»µÊT’"‚!R¶¸aa‰F$7d™eÇ Š" Û£Ó,E…®¡…yjÆaYlïí¨ÐòÓ•·­Q¨È)j•ª!l¨Z7UPÒ؈ÉAºv“y»žL‘wä%r(*`¥2 ÜÁ”ilÄA4‘ƒ‡}^uWm’šÆ1Ò!³,ȘaÆaYÚ¨´‡Ä§qÑÑe-®g´8o™Ã!kAeBŒj0€0®ñD³O†ökQF†Æ&,‘&T8Tâ$z°1ø¨­Ù¤È#ûš#)–´ª¬šŠ¹£Pgj•DaWzeF8×Y t! Ô ¥\3Hf Ü|ªÃU¦jJÙ4Ryµæ›·œáëP¾i¼ßCÈöð,j©ú¾?î:¸8N‘ö2ÎqÕ£ùgGeîù¾Dê=#že ãš®[ý¶„öûþ†»Þ^ëpˆV©…qáý”>û3"°ø?½®ŸØ7ù´ripú0š Áë”SÈ1H#ÆõèdÚs”R¤E“¼Òw,ƒžÏ+Îgáy«_œ¾rËÈÄDQ率½ZYèá/>ª3xú1îpT²¿;œHW_ü,_£LC¢#))ˆ§‹”#%áyHâHr3?aN² q;¡ùêçÑÆ…"[ ÝFšCžFÔЃ%øºË™rPUI$³*ªµ}*>¨$uXK€rT‘©ÃÇgX€p‡qÜnCôÿ…Üùƒ™÷üx”„ÂÝ#Ð$no$ãºÛùôáƒçïý^¹&'UUP!ÿ¥›7wN!ÞÜøúgÛô×ËÜk}·P];ŒÑÞ\çxÈ}¡¹z;:™¶^/ônKaŽ×¦•;üf’&‘h¯°SHÚ>=ûßm+Ñ#$Îêà@°PÜüò¯ãøÔ.%e2Ð?hÇPª‹X¿ßŒ6ŒVYJ%QFH‹ÔK÷±[#$Ÿé˦ðNpèìJ€‚¢²±D`ÔÕåŸgóù0öù2¯×Ê9o[PnÀK~äÓóèh>•µ¤(`*‘b0Dg¬×6úÄ•Z,D“ñqðà±…)“ C-6ÑÁ­ÚkC+E5‚àf-jkta–4A„By©Y¦=Zê÷QVƒ!Zƒ#EÇ3ƒˆ\˜e¡A¤T`ÄÊ+Q`|ïCÑÅ¥â^¸˜X‡ªk1äqVÕ£¸ÖaÕ#UŽ¾®CfÇ&ØV5hnþr2¢0Õ‚åS¹•1é°2ï2ðlˆ«DÎÏ€fd²À]€æš¨¯oVŸ\!­VÜcmÄ2ÓS¶¡Ó†Æ¤ÅöV.Ëc4ÓhÄpÊõ;Ò­£G‚í3»;Ct8Lm‰ÖÐë¶X6 ‡Šn¬ÈdëÁœ4¡TqêŸÇþ/ôìÙ°å¬3å+¦û 0×®ö\.»¡}÷{Ñw­ Q'¶AájÛóº)⺙p<¹àÂ)X,5¹-6åù~ÍOÛúŠ›l hNN~¿ÅÂüÝ€v7}ñŽ–š‚HÍ™( #$äTbP/·)“M‡î¶ýñÒSL+_ÈrAƒ<cžÿñåãB`FÁôîŸ!ú1µ‚ášsO?#%¨÷äÔ7¨ŸA½:¥VkôkäÕçÀs§8'œ°@ëpZYž #%ÁèââåAe`mŠ°ÅƒSø¡UD q¤{.ðÇ·YŸZ5èÀÀâG¢.×^ÎDTêvº‘rŒ‰7Sk0w뱪ޒ'h¨6ušÃñw†{wyìbÚ°ñÖ`Ó{x9 GcÈE¢—HZ-ÒÑñ¨ÁÐ܈¶ÝÌ#%Îm]*«EP²§-¼ÿuÖí ¬dôq!å&€P””f4½ C#$^~mÿú¼þç§ÙËùíá)O5Ô»—¯!,ØuŽÄ÷^;<?¿ºŠzi`CàŠqU÷aø°Ðñeã‰4.ZP)‹uF67eÈÇs„Êæ ² NŒ)‹ƒ!oóÈlj00Ç;1âê˜Hyƒ#Ü$mêª2©Ô";-Â|c®áÞË~åÝyÛÝyst3‘hÇ#N/J·^Ê,°4'×æwÙ˜q¤lÑ ÉÅ›pzE°Ì)Q’f’™PƒA­0ãÅ+#$hg]´`ž<f–j†‹´‚¬-Ý#%þf‘•s+|`ª—ÈÚUèwHn yv#%Ë«w•#£¤ƒ‡ ŒÀÓ¨1ŒÛOµ]Ú |7"'kÓKF¡§­4ßGŒ#%=‘ŒžÑ9N-î"±–Å`j0tª<ŠL²F4GL„¢“V¿²kYýÖEºSÙÉ*“ÆÁDE*Œ;˜~W䥾hÌ÷4Ýív«ÎbmÓ|‡…¶X[†xÒ­A7íGãúý¼S»a¹Ù_ÀœP^/§KϦ’¨J8Ÿqc‰”xù ÁÒÎäñhv-ªÞÂëŽÂ+ûZx†ßY«oMFä™L[Á#óµqg#$:á3m¶ƒçboÈF–L¸G’/s¸3w1–ÛsÀËʨEFj®:çdÍ+TºK.sKqŒz±µZ$ÂÕ¸d‰¶õªÚÎ…ÝšY^ئfÍ{—†Ýô^=õx°v Ã{๠‹ã³K°ˆÒ†‘ή“bKøV|Õ^Ú¡›Û†·uú[I÷r8ê›Y«#)P<N=¦,Ü9v‘$aö5£Š¨2áBµÝ&ÙØÜFÚäØv<žD?mÓƒc3š2Öä…Dx¹Ðpk‚ø¿+ÞÃ|ùðãZ’O:u=\¹Ö,í¦píœâ7ŒÞ×OŽ\ãÒ,aÁ¨!µSyŸ£°q2!Cng¨ Éœš#%!& &HHc½±e êÆÕšú>s¶µŒ†0Ð:l.Ý;æ^“wNU²tÅêUo òµUÞLªƒ ·q+,OÃwå]‚'u×!ºÜÞ7,·äµÅÅ8,‡T/wµ=cwrîsÆÓ^K·n•Êˆû¤´Ül7Bˆò‚ŽŒÃs ½Ç~véûmGQ×dð “y‰d­é÷8Ø,æòÙÝ6øi].£VÓ!‰#%0á™ZÅKŽ‹ö\EfÇhM=ŒStÕÖ1˜ÓaL¡¥ŠåšÄÌ qª]:lÄç‹' Ól± Zs‚ó‘Q‡ÍôrMðЄ¸ÅVJévöÀøV¡Œ9sŒ’$ÚŒ°œ¦ËÌÐåá÷{ŽUãr¯·F+"¦ÉëòÖ`Ô¥AÊÅ„A¯¡P\‰{†œmí/晋Àsç[D(ˆŠ‡#ÄEã?NöØ÷dce¥ñ×c¥zÍã^b0â11¢ë,J–»ex¯õç§0ðLã$‘uK‘?&TÖ¹Æú«x̼[¿ñH\M^í¶ ’Ÿ™œUC¿uJ7+—êê"Öq¸*·¸ø+›y›žÅ‘ ¡ˆ‚_#%•sqy|Õ¬‰çj—ƉÅÚB•Ä#%œJ_8yÉòÚ\Ð’T+ŒÓS”VÊ’<\G“æ¨ÀTíç¦Lšéç¡ÍèÒºqÛÃ87Œ²@×¼pC’™u:ÿßgïÛw¾âÑpGJ–:·h¼'z»èoÕuœš|„'­'" Ì=ˆ›–sX¬m™ý\Ïó£[±žÓ4µ^#%q™ÑËm´ØÿI«<dÁFÏrciéß«|øÚQ×G §|í8·-Ü1.öû[¥HtÞŠeÉÐúFD˜út¯p¤“NñøÓ¾öÂ]•È×yÃéš4Éw s¯;Ì8o,³)±ïºÂŒ\25ùX·çómf½Ô#)Ï ·>LìÎdÂ1E×Á‡#%¦Žn£",U‡±íé]ÞTnöò(öóÞL‡Ãp«^ü^VŒ"Rò½¹7”$Sm­aªØ%1…#%QÜì1Gqøì:BŠE,í@ÂÆæ¡TE.¸‚^Û5k¨Üsvª{³¦²v=ã)ûŠÑ‡u¥ ÄéuØ55…,èÈÆRÀ9œ•F†–rü=‹Î;~v ŽBý×pq½grÅu¿¬¿ì/ŸñÍ c¢Ce?q©·“Éêi+°·ìJ²\<>Ó©T ,W–8¼þ(÷å§9Š(åìsµ,€âdñúaËÛç}@î{(aH¯Ô®¿ÑØZV¨ìÁÇG{æ®uů=çÉ­Û²f|¶x@Xè5èÉMUM›yp jqpdÇ] wsE"è/JœÁ<š®a„Ú2\Ìaˆ¶Ñ–|þ<;˜JG®ãÚ%u½bs  ˆQu嘅A[^I`QÙGï¶Î±›ùæÑM©eÁB…M‚vêp|A`£8#$@uæˆâº %L[šÄ|µ• Vµ Ãvø4-¹%}ƒŽÔU…=RÖ Ãy£”9y¢"0Õ€uß9m¯kxuËlÜ“Òi†NË}¤;̲Ùùéà¾8WyÅØÉŠS¤#%gY©±Q…ĽâÙ®LëÙérFtTUÎ]Uÿɨp2pñPó·EMç³u#):ð8Á2f*Ÿ)×Ï(~Ë<#%‘JJ·d²àŒ½ÈP‚¦ V¼Å6ì\&Ž3«Ñ®Ø$d[p”P{>cçãågcÉô³ë»ÃÎIˆ—îÁ ¶œ`æ(x;å?‘,V×Xñš‡v«é4„*HTÈ0,¢V#Ö.ͱ°§·Z‰îtÜ8,f½‚"ç&c‡TÚì ì òº:ìû(ÉÝRO¨´Z[wqi½?»‚£Öå»5äù(5Duo='v土3î‹$|8é:¥ÝD^¡{c(›„B$ƒœ@w½X¬ÌðÖMª<º&LF´+Ó¥qÆþAX‹‚zj½Y±G`qaÝÐî„™‚!ÆÆ ˜ïÎùÛ=tljÚFâÜKÇ™ƒ‰á‹ëòóîŽ%û‰éú"–M<¸3CŸ9ŒpÙ ^‹MdŸâž™gT>"†èîæ‚nÍ›·_j)|%ÒÇz6¸55øcOrúùt6Ï¡E'¦ÁŒC#$Œ·Q}Kj£ˆ+“Ÿb×\ÈÿË×àç›ÑCîÉ2ènCà‚Ç ü¢q´ð ü¹Ÿ|“!í¬7,š¢ËC8í‹PR”Ö†rK¿Óp2óÖùàx’Ñi‡C§ËSZÇŽ}ùovÝzhè¯B(†%·zæø5†1ÿ%Jg-†úš-¾…çˆÌµ´.Èòš¢žPä=Ž¿¿rÎÙ/ôr(óF4…º™åè~^ëoÔ&)9¥5 Áá‚x lÛŒEcÝ=\qá¹i^¼Pôh\Ý%µB[o^Ì–{-ÎõâbøDQ'êÃôc¯0[´ö]Á¾Ìž!¦7:|¨¢¾)ˆÇÀ×'Šá˜0c¢:wÞ›$ 3`˜£Å(…ºwÄW·&”ªdo¾?Ñ#éÇÕ¸»''/Ðôvðšøw.ÞaUN®—Žçä&ÏÌÔ}åÄo·¯qëª]Sñ†&^¦ýVWªQöc°0;·éqÃ}ž‘¬[šü'ZÔ#%#$½ÿסßRU¿ËÑó^T¢øô부Íi£Ù—Q4;·XrvH#´ÁˆŠÖFšýœç;ÇÌ|/<˜òë¦*„ ¶#$ø!ä|¥SŠ¦_ž¥;AÝeέ½ñuBñÑPi¸½\ª½°mEs=Æ"ë˜Ï£05ÂqŒÔ >"T³ÃÅõ´·Â×&‡Ë‡uiÚéé_œ}±ˆû(›ï:Á/¢LÖfž­.8r‰ˈÄ<2GÒ­?¿-¡7Ui«ƒhÓŒý[sú¦§w(ð¸±ç0s‡ÂÛò³×w%ÿ¡Ø¹vËê!Nle¾lÛ©j³¾;ÖO&²…R±“p)E¡ip…šdIÓXËm˜É×׳ç›—nþ$UÚED3 |;§m™yË{‘pD÷ó!«‹%xÛŸE«º5Â:oç'C†ÖÔ^!6x–ôŸr¹IöÛ¬6úC¿“¶s›ž™쥘#%.\¡"¦a¶ëÐA:M„=š=ɵ·86<kA(·77ž«©ŠîлOåÝÌk>^ÑçV¹óä¦ãWˆ7\u~¸ñeìî"Ë’ytÕŒþ…çÜ£ì˜ÎŒwÏ/W»ÌR†–Íúï²0Û>Æ™¶Ãµ®Qñv^mù‘F¬wzW¬ûXlY¦Ö’}E)} xÛ ˜læ0B;&? ËãS¦ÕI;±f¯c~—{l×c#%È?zQb…æɱ³„°¹ÁšõRLèد˜{ÆmS”+yÔ/<ÝVI×ÍÓÎÚôoäœöÛ#%°‘ãdÛ<Øk%HóÈ…pñÎó/À¼ÃöâÈx²ÄÄ.äè…·O§0ØõA†¹2a9ãjLÒ0<WíàÅ%Îþêý#%ëQ£TÙè¤sDS‰ø‡”¾-¨KìF3ld´Y¶Ù±¶õ6Þ·{HçìnÑV”ÙHN=½EÅEE4p;9Ý4øoO™$—¢?—ì;ßnâ]HëÎÓ£s¬õå-v˜}fe¢Ô" Õy,ØOãËÏR½±©ëNK'I<"ëΚC–¶OØ<UF)¾ª¨ðÛöÁI>…GM¢íÔ³# [mñ´9yb7µºþGôÙ‘]!gëvçŽÞ..élvŸ²pË”<ýÚõ\~NKa< W.FåyýUEæL׳œÙ∙łƉdî‰N‚:§'—gCEÜÎ=åóðÙã5¬è4ÏD1¡ßÓ@P`Î<ÞÄbf÷ ñà= olÙTgœéᩱ+¶Ó= $TÂø3Ñé.°›»´ý,©,jÉ®è"š{æÀºAr*„q‡Æ£»ïçs¥*”S9À ©ÏÿˆÓ{ÞBk•f«é¢¥æÇ­d(6•‹¦#( šKÍŒÝã…ó]6ÑU@Ò¤Á+\[ªq Æ;+Œ,­]š8ý³A•vÔ\¦wýÁ™Â¡ª­”#)eØ'p.z½‹,Ò¹ŽûÄ!˜¬ŒE.nMõ5j^Ö¸4K‡ì¤:œï’°¸¸KµëÑ™uP›Ù(ÿWï¥4Ó›Hv4зp~ü´‹a0†jªH¯­×©zìuòg Ê*MY¢]»,"á„h2[j `hŽ½æL,®s>:õ‰¹•[“t—<ï ‚±ÇæùëË¿»¼ž#%Ïpîù~8ú»yó¹™íã^.zaƒ‰’,s6¾Û¥|gí­ss†Z”iªºjÝk‹Åk¥ÔÒ/¹Ó–r¬/kDTsò>¹.Ðý– ¥–Ô7:Ü#X\Mt¼µ™Ê½æ4N”;U\œæ·¼õ·©&²Á˜hÜÖ;5ù†NtÖ8Á‚×[#ÜĹů.!Å)› ðûe·–øˆg¶ªäÚ¢ò"4=ß#%g¾vç>5SAöQ%#)Oƒ¹Îzù>ú½aNwÏ?âßúL þJ¨¥­”乬†úž²Ã70“êT¦sE3Ú wf¤š“%Z£¬ÔE›ø iˆ¥×Q¬I@u±|ž%hyogr¾{»uFr‹#)Á:€È W¦»DDØ,D¶åQ|[1eg#)V*º"÷ U^q˜ýÛù=<Š;Ùݵ‘öT.v|*a~96ÊT½ð­Å›¤ÁåÌsGD^ËÈM²Ön.ûî•Oº%1"]œ÷kµÓQ†O¾/ùp–0 Õ"Š¼m˜iø<£ˆyWã’µ$e¦KjuJ]^¢#3Ì›ã›6K#)¿Æ}Vgwyç—¿ofÉã½ï"Y¯š‰üª¼½üY? k‰—…à Ž Š›ÁÑv'ÓyÎÎÙüÔQÌæeÁ2D¢¡ÆœVŠ¬9­¦¸YËs€®H¥À²öëÂnÄ٠ͺJÒµ™ÇÐ'Âët74,®u/KsÑ#%½Fu'*÷hñXM„¸ÄÚ`ÿm7ç fÙÊ·ê#ma\:žÜhtÍ·|JÂDZ˲¶{„·¨`'½LŠÔ4Y5À-æS«mz¢…aiªÍ…Q`"tEþ¾°¿’ƒyÉÅQÙëãåyç5d‹K>sª÷í¬}›À$ˆ]6›Š[¶ÆnƒU[œEEîÇ93“BMiÆ>ìÔ㮸Þaq8§MN*Ç’‡&#%¼o}É(Ú<ÖÊ{ê!s«çÓW‹7Ӵ篮óÌkß$<?Mö/.v‡kgzÝq1¾¸ñ™¯dÚ-|©ÿfÇ—8®Ô:[{·¹ó®NnÇâòaæ*버Ë,ª‰P$±Ïž:oÙ”©UÙhõÛDÑȲÖL$IˆJwè¾N44†âêmðÜùmÎÐ'A½Ê¤ŠM_#)k>>=lÿ.»ãaÖ·'½dÕ•VÍðÉm‚0;#%vf|­ð©ZœûvŠ%…ÂàÂ{í|QÎ#ýö™.¯õ-§&?§Ï,›&—²>{œÕÕ;(ž‡så"Z-K“Œ-"èâÂúV“ºÅŸ0¡?zÁ¬Ý™¨êðÎZù%€ÓtÒµ|gKŒµÛ‹b2¡ËŒkÓ]9œ1ˆ}¶â‹ h$sÑCÄ#gj;i…%"ˈ,AzìÒ±,ûcÓMË„ñ•„¥$ °bn‡f{Û¬rïÔú:=6÷8áÄÐíCY˜¸ÅqÙ tɵÝ7 ¡˜y`Ϙf¢WêuuDU¶çŒó„šØN°ÊŠÚpôž%œ ÑiiÐîHµµ0Ó,ò}Y® æ›Ã†Â³u¶ó£(ç•#%3ÁÒÛm¦Ç»XÎϪõ±]Š¡J.Ì·›¡}ò}‹Î:u ‡S¼·™h#%“RÊç¹Á\ÃCÜ(·t\(…a<õg‚gì¤1šú”¨`:STÀKV!¢2Ê,²¾nhږ󪓖[ÔUøØÁ)ˆ^ŒTA<õ_×]ìçûïöè9üðµËÒûÔrö«Ùüî«Ãš––êîºÆ†ôs>3¸øÕÖ‡Ùå7¥\–ØvPòçñ½RGâ.åÛ¬ZWŒÙåN™<_ÕD 8 †zò¥î}B3é›ã®÷øÉ?%„R\}¤Ov¯z7æYÞåK»VÎÚºçT¿SÒÀ'EýptCd/ýL78—ç#%éœao¶õQtǺkút-u¯Wz°ÖÕ+­Øç:«8,j"#)mP³û"³ÝQ‰÷zÇ÷ŒÊp§j˜Ï0DÈ꺸àµw‰"±PÇé§!ŸÛß-7ìúQ§®"!0ÿm“Ãï~tÑ.¶3¾|›ki÷Î(Ͼ6àšÆ6ãâw³9N7÷00Žrœé~…W(•#$IoÀÚõ}¶™°Äå›&©J!J_OV­°½k†Ñö|Õqâ5Rý`´½DJUoë²°õ/*'¾%tóó³ÅçÌõÞE“º§ÌUG ¬»ðéòÎ<–FB­hhƒŽz½ÂØ­J™ÔEsNçrEÕã½Æ(H\I•ÎÓJŒôØ$ྑÏÁë„tQŒ¤zdóºe(/_e<ƒ7T#%úmÀí¶1‚¡/g÷›öj“;jRÔlÛ_ë¬ui¶‘i¨GB‡DS™ÚÞ¢çÂta-MMK 46ðÙN·ïŠ“)NnK µq…îÑÐÓ0Có®‘ØDD„1Ôùé~§PPËÐB¼¸#%r„oÉmiÀ+Å»EîEu˜NÊ•tGž;!|·˜¼h~W R b¢Þán‰)Š¦ëÚÄ™‡êFGÊEs\©T[…-Y!á@¤§aKNól©äuäˆRçóup|SaOdTj~Û\Ô¨˜¹›P‚ÓÊÚ.¹Ühßeu¶ÃZ.ç5]KÐÿØHv?õMùHf#$*˜IE#XÆ]qRªƒ­|)=Ej¥ÍZÛêÔsb?«Ïo%åƒ#)ÈwÊšœ#'QB4²®ù+NUB+–ü¼Æ™ .«xÍH¢›À—]s£ë£ókju5 ©›úŸ<çYç NƒF<¼¶ABñVÐ9´Ò§lÛk#$á´á%™{¥`9§Â§#)gBn¾€¬¼¥Êö÷ÈrÛ8UA”=ô D´DÀnpnQq{,0Xš£›ÂŠgYÛ3ч\ïäî{Ðë^‰Êòé=ù±@uï#%½™ß=¦÷râbhª¤¹²ÛýÇ÷óÛ8âÃêDsQSסϷ¿Ñøê%eþ åG;¯>nðþ]©ø­ÇÇytj]&uœ¥_ˆ­AÞ­jÝö_ê…~=`0: U/]’x8±Q®W­.øßµ„ºñhrÀ¶fp×z˜BÅϾ\£ß_/FµêËç²#oäqý´æ—Ã~9Ø¥øuæt%”´W±åvžê>"÷›eÒÍDTPG;‡¤öO›ÏÍ"wáG«ZüŽ'Òë}©³ø‘sï¨X…ÕR)åØ3ëüÅ:-#$œ™pW6C¿¡ÏD%#)sØÊÑÁÇw0ÈÍdT¯Æç$Sç†!’¢ óVáw:R—ËÚ 0JŠ#$ÁjÁ#%-RWH•hœ‡4Eb9³@tBžWg(é#$V¥T$¶•ã0¯ ‹heÅÖö::„UŽm#%I£T:ëj˹K»«·ˆõG!R9…*„À¡œši£“-ÊcTE!âôØ“Çݺë©NÆ!Ú¡pu¡\%¯2猶Ì|ƒ5=ø\Ô¥e¡€¤ ¬¹ÈžÞ²Œ+z-ŠQF#a%pð•M³GQW0upómV¡UhU×Ô„Œªçl}õ¤jÒ_"‹…}òñnŸå.{Á¶Ÿ×.}¾1<Y3×WÑwß*ûŸ¯<óºêløHš*{¯†rè.—±£tŠrœ˜¹¬5‘a¼Í%–'w©6SNQáÇFؽ¤m!Ñä¾’óÁ§Zn¼o×ÏS^~dc”wï4¤3"b)ÛúÑ=¨,Ãê®»j0&uû¨ºï^.ÓŽóñßPd—úmñÇ–,áøà›ßÅOŒærF^Ò&£Ås“6¦érÒ§Hp/@ia“GÆŠ¹Unh `RþÙ½‰±×«E Ô½ˆÞ´à©Ç]#% ó ”¬§ƒ¬šÒ¯Al ÂeGiÛ¸<³Õþ¸:©¦qãÖ'‡nn£vtŒâxªxÌQôõtcšÀj)¢mˆM»v U½ôš)ƒ`Öu#ŸG~û¿È’κ¹»‡€*Ç Ÿ£ ýWI¦ªKÈfQD‚T«X´wÂõöKnqBdn„¶ç²è@êÅëFOÁE”IîµgEÁÔTº4®vˆÎGÔ¼aR±Ùá¦è©5Oèů7=G¹2Ç“#)2ºVº =Ìè+”ha#)0fÏ—aD3bíVDE¡ÑkmðM~¾ŸœãW³Ž|QÄyÀm. ”‘ºQ#R¿VÕKÆBµ2*‰¡âì¶ÂÝ£Þ´] òë~ŠÏ“ÉÌøNo5))oçæwˆtàètp?Äú{ãÈÜÇ:ù[ˆï‘âÜè K—õE”Ÿ«ü,ž-zMªÙˆòò5teA#Ý@i÷?3齑+^Ý윒åTŽQb\#%`ñ€¿‘l6èfœÛ Çá„ôŽGóC¦Kâ6bÔR|˜>h‘°ÉÄÛ n–c°¶té‰~Ý&¡É^;’tÎû9¥•Œ²s];îI‰«WyžÿÑ6c”çh…ÃýŽ9èrjiÜ)á¥v¶¶#)Zd8^<ØÍW‚Ñ6%³œSø «rU»‚™“RÍ'šãÃðÞÜ@°xWºNLMü:žHíé¿nÕè€Û–9úyœ,&1¢¡@ùézötÅŒÎÞTðøWŸ#)5ÆŠYmA`#$uìLž@±†ôÖ-ÔM{ Ä£ èþýUÓ£•€P=Ùú²©j§U<¤뀩‹‹˜+fÁÕ‘›ÙÚùk^q¯§8x ™Á_MTVüô=ã#$'l)ó*Šœ±[õ=Ú|¶DgÉ=¡°t;}Ú2Ùx&ÆV´7ArøRz6{¬Aëô®Õ¥ž?µ Ö áÓLµŽ}#%€¹FËg<æRïf„îgÆ—ML:ñS:æ‚ A"¢çN¡[LJûQQÞ+J¤ðî@8Åz©ü“ö;bffüýžîX‰u42z+‚&KRF”ã?Ôæ}Ä–!\زVVQ¨{ž½£*y#$˜L!Q áceµpJpiM%Úx'¯}ßòoP§¢ƒºjO§b<cÄlÌËÄ,½>fä_({²©|ûÜä€@Ú»çóWWáÝÞžHŸ‹wMtl”¶¯Ní¥#$ #)ùHOIÁ? ~€{¹QŸG ëÞ>ìæómDû& MMËú|n¯B“{Â)Ó þnŸ§þF9–—ãl­…Ó%ýçdPûÿ¼¨qF ܶ$´ŸoZWñôTJERŠÂ,") ¡Eg¯0ñ`r1"B~œ¸^t?·äçdÂeÃ[Ò±ÞLyl'Ý|Ôøy•á!E`)$$ ¡ì!¦xXáØQÀÐ÷á™C*2¸ü|LG•;UñlõjÑúÓ͙ژlØ>Žé+ra*÷6²ˆ#8_ŽÎЬ( V>Otxadˆ—ì­³ 3n±Ç¦n¸‚B¨¡Y‚¶žÄø#$J*”C’B£IQ¹]éžßéâr=ÚJ(xþ5ãséÏ_õ2Þÿ•@/=tú×JÔÍh­(÷ ·Þ$ËCÀ¸ÀÁèO»‚¬oe.F!QáQxm\ûG#m@Ì«¢·Ò>#$ÙµëÀj?›#)þÿO¯ån—B¥<Ë´˜fÈj… ÀÒ’çåIé]Rz`àâ–*€*_‡ÉrGù©”ǼüÛ™Ás#)EVƒ¹E|vÛ€÷ã&Dý¯Ú¦‡÷TC„ºI¯W#${-þ7 ;Š?!cæsŸÙ¿Ã¡î4œß]p¬Ð!T¬Ëp˜Lû­Ùó¯Õ£âû‰W3Áq*ЃtT•¢T²;Ÿ[•#$+~áª;òÔQüa¥… nzŒÅmµ«Yn˜Š9–¢¦‹0Ïþtw:Dzl¥€F­EýñžÍ)Ѐé2P±Œ(áE5@röÓº„rˆ}³Ûì…áQ#%–÷Y#»çþ›k‚‡IDEOFÊ;çlC¬…²‹L|¢Èa_+™¨->,¤#%ÎÃ$È“ƒ’jPmHÎt‰@íа¥Ä*i¢Pz¢ìóPñD2€lý<õïÚbÛkî'ó@*‘¢úŽ ×†ÛC*¨o¹{@ð«îqÉ=¡ećÇÁíŒ#ªcxù¨_#$¯ái¦»ˆaÑ$l`R&5¹z'Ù![H‹á¶÷žžèrQš2ý8Y&ßçvˆçÄC³i˜‘ETž£¼ÈR#òdü^Ÿ#)`!±lœ÷™•˜ÒqÒÂÃìU¿,;iùUÎÿ•á›µ ’éÒYßò·ƒãv÷ÕŸµÝ‹p“B ´#$þÞ€ÿ^v†t‹å»õQÙË=æ Ÿwím¸P¯z¹ï%0F,8="å­¬Åà0B#%AÞS¸‡8éý—BÊŽÚ•›:¨žÊðwC|” P´fÄTØ¿SsWxË2Š5(ööQ—iå¢V@vB@Rª` :\vñ·E‰>0qVŽ«fN'g~>ɔŚÄ½Ãi¤+ 4AM÷ßò¹¶ *r&lÃwN´5jdHÀ™ÒâçpL¡Œdáš›È(ð…îŸ ü2u…ñμ»Žf%…ØÁ E«0ŸT#žmÕå¯Nz^¯)¤„}â#$§T+q_”À¢ÉBd5š¨#$'£ÛÌÁã|Ð%5ü®ü@˜Åå$í»yë÷»–n %µÉkÕï¿€$ØS"€ùœ?–IMȯ ã @c®™äšÄ…A†´#%ÛDhækŽàf@bT·U˜”œ•wlÒ¦E’²™F¤Þúä/k<»/ž/_ ’|P8WÈÓ&=,Ñ›»0E“QˆÈ¤ä™!C*S'2‘?0½å¾P<õU¦¾\É<¹JŠO/B9Áã©È®²›>6H;ꄲqêôåáÃ#oá¸ÚO Þ|4w~ž-ÄÆ!甩Ù8ôp/¥ÄFÜ–'|#$ÅÁÊŠdSC–˜Zöny¾À:cNEñS“—¨âŽ¾|0d1×èPÚùf>§‘;ô^;zO(0äîadc®W¸ ¢&#)ŒÈç¸#)MNøàé-r©N3pÍ!lHåbê#ü:;†W€ò3 \ä ¡­³[…¦Œã0¾‡¤ƒ±Åò&º¸Hæï¥-ñ±ö+ŒÈ®¶›û+èbq¸ÈiLµ6y–ûʬKka&I‹ü™ÆIB%¬`+ncXÃt‡ÔîáˆíÅ5·AÏyÛ,aNrœJÝØRø}Ž7NG~Ôqaq/8!Õ„åýQã¦s¿–ôÆ ¢:Ó‡Ï"æ[ÏŒã¿LŒ•ƒ²SÓ}/e{M£pß1èÝCïànPIßãËAØäŸgÛv }؇?O—I$¯/¿¤¿ºýqîë¹F«Ù‚¤îTj¾„˱–#‘6¹ƒØÌýèßc=½ñoU±¾l/ë)¦@ àPC¾G¶oÀχ:r˜Ö¾[xäü%~j2 RôÞ0ª35¬Ži¿Âሊ¹\¡–ôUºÎgP”ŸÏ".-©u¿#)l1£¸AÀIB&Ú¢Œ˜\ql\¢Ø {øÄ#%øpa²šÒµ íc-„ºƒî¨ù÷‡Œç%g¼ çugÒ¹¶ÞåaÎc)€G¢¡g&þ#)q\ƒA6*âÊì°ëü±`½ÓæâµívÜ_ ´ùh²ÄÜRSh‰i2+»–šñOÐþÊW³˜î?Hs\xâðvÑ•ËýPÄöv2&/Ýpe0T»¯Ïs#j¬)C‚[Ø $¡#)Þ:b¤\CÍidë;ÈЪa,Ú8­ïÂÅ*±¥P:¡=uÎÕò0Ó!-®øvAÍc5 Õ¾>{\Gàp­©ˆîø~äÐÁ#)8éžîo,|QÚÀèÛq"x(y§¤(´¦øËåJ®‚ôîׂ@¿È™ÛGï¾ÿkß#2CÛ§Ñ}â±Â´ß,Ç7`¶ÂU³@ÞÔÛkÆ¡Žf­W]³åEAuÖ#²ù<ó×N˜g}vØ!ÓÛÑò”ÖFÅ}Ï xL‹±2mýÙÛÒ²{‡ʤ—¤¿ÑÃÙ$‡¼à~;GnÉñÕùš6‘­§Úº)ô½âï›s9a(0.#)ªF“aó.ÐST_Ž"p±ùˆØZˆÎÞéìÉ2ΣÌƾKdJå!ØѹíT¹ø|1<=²s¦>9O{55ˆÕy¦D¦|õñ=ž ê®G¡i—3ÂfzÄÝB…JªO4bÑ®>m÷eWkZC9š÷BhBöT¹^þýùô9ù°:öãso‹A—f/-@‘‡;·‰á5tw3ËùrXn€²’„Kî×é0I².Š­–Ê,ÐZÅV‰¥áEáÅ5XìöL$·/Þû±[Ô·§íŸ6ýå‡ØûÒ&5P9êÞóŸ¶;xÅë¹P±§ËAgÙ‰äpδm¨Ò5IÃ[{ylè=ôVòcÛ¨¡¾5{#)JÅMZQi"Óc#)m9÷kòï9Êa«:ò7æq<xJÒ€Vx(p¨£ÐR  ½FÛ€H1 º0ýÛ…Y€ã¿p…Š‡›ë«´Ñæ3· [¾æêñ 0×Дþù#)âHŒêZ½ß®o^Ηíóžô„›÷‹þ¦³Ó»åì箑T ?ée¿æJa‰Ü"¥6»._¥;v¯<ò¼ŒQ¤•XÓþ_÷½ÉÞµM3Å?|·ô±™xøŸ¶Q5OÚ?›$ÈB"Wáçð«á ‡…~  ýñ} ó£Ë‰æÆpè>¯g˜0÷Â{ñõéìÈ‹V”ŸÐ‡bŸ¤€¸?ª@ÿIüŸÈù¸ÿ¸Íü¿w×ä?áÆžÉ)nx)§%@‚—À rÖ#)G˜#)|z4ï(M8Rë×–»÷Ü*;Ž%9ÆéóĤ=9Øꂹn4\I­Tœ§A nM«d³ðáérc£Ç7!ßêÖÄø× ˆœ!¯ª\¿…Pc#)MìO›æKò1¥óú(w±4°èchlH¼±Eî!Ûqm‡c~þBD†„Ë#) $8 ƒ>ƒLìÛöQ¥ú[ò?ÇÎÜa½¨Öˆ 8òŸ¤¶Fø`c9îíµ¦Á~òç­ 84—ïêYUß‚;h ˆ X#$Qø#%²;v°bú" 9¢‹ìîühÜ4ªßãR§,<ØŸOä°éÊ¡«ã¨Ý™I:nBÖ#$È¿`ìzmë$†Ç½“Ä}œù´¿¼ØH<JaE¸ÜCòÏéȬüz~øîî©D¾˜-¦Úš îÿt7‹í"xaK†Pô V%Ad f.³±@°äƒ”BÌ=lTL`‡TG¾ÆÅ9QdBÜÀ‹Jk)€_@.`˜#%[)`?lsóÊE¸dš–KREºš\¤t¹AdŒ3(hK©T&Cžë vâÐó¥6 ÂŒ¶ ´\ìdV; FÂF…L0R,\d©ˆŸ#%ÑA â¯ô¡BÛ=‡|~Ÿ?R©þ›s÷]w¡PW†æ@3A€¼°%ÌÁ€re¥Êì÷ÒøE%Ü#$`é¿`|äy¨™¯CSÊQሩkÛWe ÙâQ~äÀgÍ>Ñú/Ÿ½ýÍOs0¡=–˜È̆ËI31áãz¢tí">µòÆ#Ï1Þt®³}î©ìAâÿ|›g:ËNšàÝÃ9#$$Øn”r÷Y<tÔ'izOì2p€‰‚ö#)¢#X¥2Q*¬AbÝòmœ\"&óOe\š¤“#)'nÑQj¦' ^#˜qš²(¤© Q“çU1L-NA÷acàxÕ¦É]RÎ#)8—5j#Âq«1>Äìœ'w˜Ô djI§§íjÈŽÎOhê¨ÕeSþ7‡hø´ÅÙ’¼.ôyí6z­Ë¶Źèì,ô©»›à+#4åž¾xãã;àc¼þ™±M‘ëq¶–À5>Û94/`x›º¼Ä’Ÿž#^–x¹# žEôõ’Q¡E"°R1HŠETi4²Íi34£õ~ó߇â1ÈÑUT ,¢ªvëëÖd8̹ÌîL¦›M¶hîunã‚ç‘k+´f.è2#±¤fpĈĘ›}äÉ 8ðÂì(vG°ìÖ—3¥žß;?«Né“|[XÔ”ï Â#)B)Q6ì7Tmq2çKž€sß#)á¹Wu¨ЛÜ]Bì0†”èe†DòÚ_1r×› õ˜ ˆÍñAÂÐÃÄ>ñ„ &Ø4؛Ø`|ÓÌ}Q(ÆΆ´pØQª%¢¦Þƒ¯Ïmq²}•|jºLÕSvÉÄ7ÂKšã[ÈÓ¯„ ¸8†'‰éxÂCÉWr=‘ ¢–#%‚iXìwXýÙÁ]¼,qø)$#Èzéc# ðœS¹<Ñït²'ö(v2†I#)×Ѽmµò×5²V±­,¶’­ŠµdÖÞ*ºZ¯l:ïÈó»ßuÚ«ìûÝ6JJH´Ô…RØRŒEvÔ9 svlðƒ¨IáÛAIBØzé­ÇP3'K̂ѻɛõÄy8R)j4Š¸~f|¼>_\ži5<û“s?|y@£¥}n‡½hð¹J|&/³Æ¡ÌÓº|¼lY'4‚0U"$"€,ˆÀŠ”&Á´—ÇÀ¼ï’™«xÔÝÕˆ`ftË2/Yݘ%žÂ7¦¬ jsÆðdÈ#œ†Òð"Ú¤¥”™$‘–óÅ:aÑ y»Ššä·úVº™skï±AyDaÅrË+¡ŒI#)ÛF¤4A¼ #% *˜¥D"H„"ȵs·íC"¨‚P‚Á* J‡mîæNcôãDïÒŽ“¯@0v‚¢-!TVšôÄ"1BɵOl–0îfàʸ#fTâo¦z÷_ÂbúñF1"‡‚Œ¡6Hj‚"aN>»wC\ú6×d=}]”®z<Œ…tåÕoÅ‹1¨”Xy#%KI`ɲ‚ G›eùmã˜=‡G Ú#$›iÑßÄ’<’ø”IÛ;yHsT*u×UášÊXq¢È°ƒI#)wó£¥Y¿ÄË"ô5$@›š¢»£–w@Nɉ¿f¾˜ì¬KBC†æ#%ïÃF¤ ó=xË# å£æ¯¬{–Òú7øŽ}Ð8Z’4ªñ'¹‚ˆòB§ÐÆ,h¥!@¸O{ɹÓ5]Ý(–‚èTÅ¢…#$iß5Î@ÒŸ&ó9”b°f„‡¸JÇ%î=Á×ãæÅl~fÐÜ)¦Ä}Üjq¤¡'°d(Í´'ƒä©¢Wʤ”D@É‘0Ë,‡EÞ@¡:{|ÑÕ ÀÐæqÔª¥ÆéËc¿yæ¹’ÜÏ 5XY}V´ö˜)¹xZzwwy `6eÙ „Ù”Þ¡þ·Îl+¯eªñßñicŒ‡;%™¾// aŸIA¡½#%3Ÿ·×ÄÑèæ@0‚¬21¶3Q/uÔ‘ðï|wÔz^îÝöõ±§sá¼4=¼Bá÷D¨ûzÕÓ­Bá“…“·ÍÎó$œ>7¦üNU<¦Ô$À,&øgâ†a¼ygѾŠƒs,³#$q ‚`ÛÏC.ë•q—»K›ÓKUB¸ [£ušÅM4£Cn_‹ÎÌWœ¿Œ¦7|Xê> ‹Ä>'ÛÑß;æ×¹uH†‡[§Ï$:úÞì#)D8ëÛ݉ƉgK•\!S£›ÒÚ 7E÷vã»·4€ªKFˆB‰- ZTK=H@#)AbHéâk#$•5¢Œ¦îi9ešÑÅÌ`ˆ¨Q@œò|iè‰Ò¢¥Ój ‚°pMzvÂ4Þ§žLhÑX·J(É:C«ˆCk…YÎ_"Ë)Ȩ#)M蔨#Ý9î,ó]»íYôÖñ{±zÍÔR´9ì®ã¾o|u—ÉÔÛ²Í;§Xök)l¢Ís™ö¾‡¾ÒÆ»úàÖñÜs¾·²:£!Fê bÎPÖxÜ’âw=E†fü0Ô÷ ØTVU;@éÝ‹ìÐ_n’ˆux#͆vØ)š•PÈ·£Ñ}uò>dÞé­rœ´ªŸ™I}q^2úqä¡Kg«}'Ð% pÜ&ƒ!^#$sVE"1rœN”³q2M’»h¨œ>°ŠE=zê),.Ôœ+u˜enGpaÀÝEÉÎ ši#)öûÿŽÎ¹Ë@Ölª"r£ Q"BŒ-a3‡–}%î¸Æç’CÀv|ª•JÈM„?3'³µ{yé¹b+ê¨roå¨åZ$kìÃüãSÙ¾(l.o¡6Èîûìn<4”ç] ìS.³¶å,ÜsL“M£ä6H#%:EÓû¿LØ™çÓZ©#­i!Ñ:®Î!y¡®ÌÙׇÂò׿Y¨†ü{Ã1)1­„Vyê;KZE F¶/†o¶g#$e‰¸Çlî 6Æ;?§¨ìI•àÜFÞDx?×Âë´(ã¥@Q‚ !Œ]‘7N§’47k'•¡•k¥^÷ÖãœSaÝFq8æj\Ø@I¡TWKH"Æ&‹Ië]TšL˜™§­#%UŠC ©Á£FÛ)j…ÆMqbißSsÚs-HsÁÄ©r#)ªkD¤Sp‹'Òhû¦ŒCÕ½7n’ëóì:go8™g×.°<Qñ© Í‘`¢šŠ|*x,ƒÚ$õ%=õ_œq É»#)ñÁÕ¶@8™¤ð…w@Ýß=¾æ?Å_#$ÀïêØYÜ[^› Þ?pщ*çÁiKûŸ …®L à–?@w?gÙŸ2“B“ü¯Ãyìο,ñaèÈ¡4y#%^‰g¾¾A™¨@#)|¢€ÃáÃ+¿m#$O¥FvÁÇ"`>øV%ãóÞ‡T•¤+Bé]u{*½ä³Ãôþ9†F4O•‰ôï×í©â#$˜â#$›^»/„2Š\xÑn^ ×{ï#)qªÈšDÃï¦á.ÏÉú@qr¢z˜zñOÏIPæa‰íß¿ç˜c€o¨ÝÚ'³¨åá×xÊJ‚nÿ¥øâX¶³OÅF5ÇÔ€˜œú#-)0Ûß5òš $Á!˜}\ž¿¯÷}Жüó á0¶(¢¿¯÷ŽÎA‚fd€-RtŠù?ôÿƒÞüA9ÛAߢ=ϦÿlÔ®¯FUýGµ¯/ò¢0ìzÅŽH¼¿VaÚËt.»2‡yòˆh€€ú—¡Q[^Q»‡àß+·Ž[z¯o Ezñ®¹DE‡ôÿ“üÿwÓýæþoéüÙ?åŒ9ÿb_ýò곬ñŸe#)¹xÚ]÷ÌÕáÍõþÄÿnÚÛ#Û]ö«ÛY}ol*O_—ÅëOÞ‹Š?ó€$f'Þ{ìw¿Zœ€1SLã(}kô>c’[glæè šýÖlaÚÚôÍìç?—ßô¥¡JZ„à’{Áýÿק)ïÉÊ)ÓέoïØmÜ’d0á ›Ÿ§ÃË¿•EôGÇ^8ÓOçaÉ…5·÷Ë–K%Ræ¨ûUÊþKæO#)#%ÆFþ?Â{ŒÆ¿°¹«÷sp_¹ˆî5ÌŸÝQýžyû¿ˆëﵸo›»ev¹ç€´HŸËAÝtlÚ¬¨veclÿ!4eZêE[m¦]2‚sLž<‚ öžq¨.`@V’R‚⣎ñŸšÜ3×,œŸ_ü­Æ¯üN&³Ù°[ŒÛ‘ub¨ÕÒ:V­¢¸Â©ÙÝ;Õº)²6Qu6þ!ÂÚ^„†ç‡fbPq™Ï®ÖÍ”ÆÚD6zíuñ˜#)ºÊqÓcþ¢-2ëó=s³×eŠË<jü-v3°J#);¥_ƺ/ˆ÷ ”åE#Y}ÒϯÙóãôºž”GâU)n1ðåøIÙ÷ÔÛöÜÓ_rãce#5]uŸ‰¯è¬ ÅÛÈ­K¶ä÷<—ŒöýK™ØE]‚ #)ID~Ÿ‹ÂÃ׶ ~Ói³/¤Çý0úãáXcüPÊÔ±ˆ‰,‡ûÇ.<ýú~‹èÕWƒ|¹ÑÇ„œ6ƒ†lXS (û…p¯Ç›”Yòy6UÓú Z1Åm™`7'Έ#$ˆ(e#yÚáÃÉÜ6oÈp€#$‡“ß±ƒ£ðÞKìî¯õþ-´Î^j+a¬yαm?.¹Ÿœc§ù½+wÜ(LÌÁÓÏìZ[»žIÿ㻓ê©H"žPƒª#%£—p€N^=•È­êDB¹Ör…sZ;~¿Ø½Ù=ÿ±$…lp%þŽú=!€ý¬zV×è‹péâCsr¹Ï¤,rãäÓñáIââ{¹JkråhòÓôÓ×(Ž}`Mù†|†YûÀ#%v†ît_÷лPcñ_˜¡#”~¯ýü^Žýuˆ|Nh¯NÝÓòÓ\{Éþ2=+{âÒº°äùƒRr¸cl sNÿyùñGçÏŽWìóøOðwŒG߈ê¥|Qñ„~ÏÌn¥Ø`6ØÁm3ú­ý~m#D$•Ã›?Pïòù“B(xäñÿFã£C.„*ê¡k=wȹÕÑl´/ÙÎÇ”ë‡õé@{;ŠÔþÒñ—»ÇN¬ò±O>ÍÖlè}<Û™¨­w=7ð";Þ¾Š.Ÿ‰×i¤¤GEBø>"œåò`m‡s´éÂLÉ #$Qê´ÁÞ¿“…·¨Gvþ\¯A¥=’`–„ d¢yUzœCŠäæŠÅýDô#ÕXÚüJ†B¤'s…êfqUüœo¾Þ}“ºµd"Èr*”̹Î'.KK3‘G)žEœ&Ój#$@W•ÑȪτÈA”Ùo$\ÑrÁ34Žpê2FñŽÀÇ__‰‡Uò%Aª¤I©#)#)"u±#$¢ºKj"ÊË+:ª°z»}ˆ¸ˆ"ç‘îï¨EÄO=™?DÊÀIË#¯@#%Û…{òAÒ ”óHßC’‰&hÒ\> –ü¨ˆ€}à >¤݆ ÀwŒÜkÃw‡÷Ô@¡ùôa¾æ—°?§\ [­¹—áùV$0ü蛬ñƒØØ+÷c[t¨Ü>1½O.¦Ó "s¶^ ‡¼Ê_•°ÀO•GÇâÆ¡ƒ\jw€ÜŸîï|H Àý=|½Ž¹ü€®Gíí>|ß‘Û…i¿/òwüu+ìíëÜ¡ 'Dyy~eñB7\ýü;-åÐ9ðv—5[ujŠ Ž¼¾bJr Õ;‡'àQ6iB#¶O+¯Úì îg~ŸIHúVí­üsüA‡…L#$¨Í#)~ÇH€YÇí‚zëaÛ$P…ªæ‡¿é[è¢ÙÏb»ÍhcDr‡ ÒlŽŸ·ö+êAPZ  ˆ¨ZÅ¡Öëz৅«$uIŸ7*VÏG­ü¯ úåï.ä^’úGùk#ùs=$¡.¾ëk'¥ü ¡pNÛ̧Tï­?÷¥ùÐæ AO;‹Ûßï­BîG÷g˜Ö¿…mx[¿ÚÓÌÖ^ëÂaPáá­L*w§«ÃÅàϲ®×{x{U´As\C˜tìÌ8ëÓ°ú3W<—?Òøþi ¶æÆõ„DUÕÙüíÅËT"ðô'{·_º#)•IQ'J:¯MlsÅ^醰ù·pˆy34u½v(jPq•T_>gÉÿfˆuæîÈž1÷Dçä\ÄãÖ³.Œèê^ÔNœú£mIþ×ͱ$Ÿý™ƒç­ñ'U碡ñó‚û (¯¼ñ‹ëÍ~5U:èu劾‡€¦w¾¾Xuyyo·˜¨ÑÚ¥6ÞõŸ¾ªÇ8sï·Ø añ»³­¶‘i RW–FW´ÏÐå«Å„Z±ç–j®¢÷ct/Êá•:X‡÷©+U/¤Î-Þ¦MG¯7F‹îD#b]lì_º}qV;ÔöÆhñÎÐt·…¾Mç^{Íඌ˜bµdÛÞQþLÊ÷ë´tÛb¾/Ÿsºj0AÆ ®+M¼¸£”é´_PWMîªÝ:tçñDË?~Ä>1^ÕÖOWJª(ž›S'Þü“šÆf.VÐO‹¢vïsγÓ:ñZSAh?dfœJb.4S¸Ã†›³ùœOÚúÆúý¹bÃ(:s)0RôI¼ò¿#%yêjª«³Ñ½ùæÕ·BÌ;{ûÀyÕ{#ÍæjŒ†ä&7ô çÏ_nÅÅ¢Ñ]ErV€S’¥£I#)^ûÙrÕŸºŠëš[Kó—‚F~Kû<¦Í†É°…û5«ª¾úVžAÀlËóÖd!SLÒk=£èvÔ|Ç ‰t#R~©ÙEé÷ÃMQ˜’.á]"EûÍ'?^GpfóÛh„-ÙÌv÷'b*–Ÿ.:üñô‰ÌÄ<\K.+ŸªO²Ù×é…Š;6oÏ}Íú¹s2‡x7ÏÅÖq Aî!àÐÛÖÓN¸ßzÛ8í3‘ÆéN¹pŠáMO2Oã6]þâœá§î›œ˜¸ª•#)Mê¤ÆôlÐòQ*€ïo”üY°}Ú;´*ÐV ÕÏaãù¶½·¹8mÝúÏ«¯âÌCÎ2ñÍeµŒ+9r úÞ#)—ãþ4Ç‘A¹Š§Ì86O„o•(Y¼“Ð%Ì–ê‹@+ïÉûÌÉÒ°n7Vª.Ï^öIßSG…Ì$‰A°Bn~m¡ZØRC3)GñÆYÂ˺{曡¡–»óMKýÜX°æÈ8ãéé#%¶ÎËHe[¼‰SËýH…%"슕ô¨G λìUµü£Øf¹ëõÙp²{}³1µä¼ÎƒKZy3^åÎêÖ"âXò2ü¾Gôűôó[x'ýq#)Gër>6®q†õŒEfXÄJÚ=;³ŸàÚ‚ûká-¿Òü£aÖ%϶_Ö߶+¼äâ«ÆB¯„rMù[]¹4íÔû\uëão»½ÐoÚEþ½Á¯Î×%TdZ@Vàõi¦LŒ˜eƒËõ Ü ø½`€8>¼Xï`·b ÑÕ61›YŸÐ÷H ºššÓÞ7õz°Ç»“òtmÓNubÌ6þ="ê3'•’–¶üJ¿?qü'ÛŽ¦S¡Z–0«+îùÔògëu}âe6R_™â`ó6Å™¢àˆïÀ„Ð{Ã/’cõÑà@–L}=6ùã #)H6œÔŽ8{ù·„Žµõ{~pÁ}¹ü.“› ö²¨“˵ì£AÙ„¤¤Ñ÷¡gÒ¸3ša¤ÙÁ0WÁ¥åO£ãŽ%×ÐL´óòüŠéÕÛNÎ?Re(éò‚tâaâ#%·Zô˜åî<;#$«H=É ü·«M´ Rƒw+ ÑaJö0£ˆPڸ朒zƒÊÀïí†#%xybXÌ|~ožá¶ŒÉ÷U„éå¿åPÔ˜ø è6Ogyþ/œ×J‰ÑOñ ÷Axr[ùg5¨ù(龺'C~·˜é øLŸÆ¬ó_^#)óÖÓ²#%©ÙŠÆŸQ,iLКvq×8™gçBzÓËJ†Œ^ç‡ÂŠß‡×&SÖÃGÍ«ÆB6ˆWÓˆ½É÷ØÈl°n~·õ )ÜÉ.òSÁü›;÷JmuÜ©VÅ@ÎF*¨› ™ÕUþ`Î×âIŒ´ Ÿ#)ãaÝJN îaÕ—£‹9£Ê¡È¡NŒ)(}Òv8a4º'¢‚ƒ#$ÔVÒ¤Ýg—i[ü7ôcæ <¤}»-ˆáæEºÆ­ß–!©ö{eÕ´zã´± fA (ÒŸt’Iz”«$¬T#$)‡Š¼aŒZ¢Â—€ãr?t*(¹Õa0ú¥'I#$ 2 @‹e5r’È3ùÜÒª!Pòy%7Ó³¥ô:‘­YÑö®E‡½ÝðV+Ó›{Mó¥ø—Lw³-‹™†qÑvyD©†rõ­ë#%;‡z?4צ˜ÅC­Í3µC逎9c›÷}cÏßu:Ãú’ízÐör/º„!vr¾éˆ»¶`è!†wcõ6}Þ¯ÞBLM|¸ 'ϹÜhAûôŒd;cù.ÐXËüÜS‡†E‘aÀ–âK§î ºX‚Î>4<~Fê”W_È§æ ‡²šÂö´#)ˆ~â'ΪÇqOèÂè8g  ò[˜w zõmý¡Ñp% p!£~‹; *ŠÖ@ßE“Ô3ás©.’#$Æ¥gþí_þ¡9€ÂšÈj„>U÷g}T°¿­ï}ŸçÕ m¬è`ÇÉùÝ1P<+Ž(o¡!ˆýFtNb)Gúhp²ßà>ú#$¾ÿPdÞó[9@jÕÌ Rˆþ fWAâ¾?ëDÏÇøÉ£øEº#$OG •©§¼_}•|nؽ#%ÇSÒפHýîòǘjîW>¿ÙöscÉè)$¿”äå`·æÌ<‘FûNwŠ]Cá<eŸ¦©P®æ#)‘ RQ-ðAÑîBÇì-ˆDßAKQázÓn©cÛ¶žŠã÷GÏ‘$ò*Á‘ƒõüGíCéçõË~žÞ.A˜÷ö¿âX¦ÿ™|q€™ŸŒßòéIaÔö?ÂN˳àüÅÄ° ’s l·Øõg}KÒ§`ìûój³Hòb |„HcÄól@À|eF$[EÅÞ÷=¦|¸VÉÃ̸“ðr"H‚#%ŸE²óSžòáxäƒÛf‹—•FŽ+mu¬>`´&ú—"ƒ˜~ÌGÄõýÚ®ªêwfÄ8§ÁÜÁ5(jðTÛÔ3”×,þNN!J`BUF#Ö,¯ L’œÄHR¨)¦¼0¢ªCI»¾¿·ñÝõpÃdÓ»aí9úÌa0BD $O4lÚ)PPíîúÞ)¨E0ð¿,èý©ìåÔšÃÒ?f`¿„Á<ø8鎃»ˆÜÇÓ\óžx_Ë «áó;y]6DÝHvSdH;åî’H‘ EÆ^ƒ¶/2K #ŒDNZ²/X¼®tæQ& ýòä#$=0œMïžòkðÑ@¥6ÔÇ¥ã¥û­ÍÁ#%¿¨kK^ýÞ“V_ó`wÊ~ج»…h#$³u):ˆÜ3o¼M„–`Mtv=ÑÚ”ËLæÕ½#%g”©ØõdäÖÜy¯ž“VÄØRŒmʪç17F~ŸPibÎo{T;ðÜ7LÛ,®&»©1Øfe7ÖqÕb·Þ`wbç×äÐS:+ǵ8í\RÇ`i>Û¤94©¨ûA=}ø0­½üo;u˜èà ƒ¸§Aùm”P•'@î}\ò¢¦Qˆ€^-ñƒB@Lî½PfĤÀ³e!#%œ† ˜¦ ¹‘)øbñISBò¥YøÒúG¥›…{G>±¬.´ Áè4aëã£~í¥aµï†¿)Q@Ñ(P:©”©mA ešWå‰åmc5 Kù—Ψ¡#¾#)½½_‡›ý,ôe3Z ×Dæ‡WÅ ³Ìs½réµ…„=o?Ù¯hmWÓ÷ã{¤üt|Wƒàøf!Á¼Xp=\k©Â‚š¹–³õ}«Yˆí5ŽK_þnÿXóhÐSÚµÿ(xúà§þoñËÅN„’WŽµWídJl/^•ÀòŒ 9ðÞ~%V¹ÔýØÉô¶,¿ÍÕg€AeLD®RDd{$!c“•SÌ\8t¤#%¯žàø”#).$¯­Ã½ÒÆ8@Va[…©E¬û1KšnùŽyôÛ§îG9ÈoÉrŽªÍÝ$W®ªU'I2gt©/ݶ‘³kâœâ Ùz6,•4éœ!Ufœ¡Š$ë{žû<_ã•)gtoâ´C-žnÁç¿)d¸`(ä.¢V¸ñ(#‹¦1Õ³ÛD0+^7½'k…lò`ŒdÀðV¨jÇŠ&døý—Ëe’ÜñÚŽón¸\#)¯Þ|ï¼hàn#%+yÓR³:ÄÄ÷N'zŠP £sU‰–=QglZEfØ pýê/©þ¡È0 ø#)â‚Ìÿ0æ¢z"Ôæ2Áe¥™ìêVº" dÐhŒ‰Q’i½vhg*ëa®‘±²¶89¨¥¤óˆ„¯O¯4fÓ•†2茿clòÓßÙ‚2¸Úáû;'¯"ÿ‘+¼“Ô.’mëXÎïaÜÓÍiè¥iÙ²¹¿/t¡ïßÕIÒó„«ãïíÒô»z§öâ±Hf`ÌÂN¶»±sJ®I¦Ê¥6 u,§4)°©¶ÀHf¦ØX^+¸Å–Y-Š¨àd!#)…w&ó0M)dhÀ Ê÷» Ch7#)•Hj8£PCÊ^,°kÅHŽ2ºÎC%Ï7èÝatNr™oë0þJ"RåìNÓˆq†™H)`%\‡ðküù8<½<Ë{Ç#òÑnÓâ|Àò0VÆ5‚“‰ Åiéè{ p Yûý#%*G²¿ˆÚ8T°MˆÀbq¥¹›ÖCúw¥‹öÙgâ³#À}™õ«ôX~]W§Ë-åöü~xËŠEÚ¥ š>]µ1Á¥'f´z¾u£º6´í„ÚH…?/¾wƒ¤}Úœ¤…‡aq´Áäãdí*$öÎ;|QÜõ‚îœv?¼„ÅX{§§nª!ù/ÙÚ~]ÙÊÖ’HçÅ0J×ÇDi—.pϼ «gLlCgø+¡¶KÐòÅÕ²gµR·¢¥kYKÑ‚¸!(M…i1 züÓ¶¯Þ#Ànª»Ð0¹P#Ë`³šAdºåXóꑱä\²EŽ™‹ =¿'›KìœýAÊhµ¥ŽlG¨‡æxX(8zœÒPâ†#~.½3iÒ<#/EŠÁ)U‚SmÂ8 Íåµ(ôÓÔžO.‹tI)au0*Û¡º!4ºOÓ ¤)€á‡g§aóV¦ƒ¥‚“ëž__ DÓ'8z:õ1=Ôr§ % $ž×jD¶›U äÏ£Ê-2§"lU ´_ÞbLê¸óûYOÁê=¬@…·^·ùìü4-<£‚ŒU¦”&;Ïo…^âëBP&œÈl°¡DMú"vŠ¯aTçì±j@Ö94E/}0·]«D8çnÈÝ 5²¸ U«—µÝ§á©€}]@W:ÐBœý,áçÁé §D;aA¤ˆù®­õé»f~¶¡ÔŽç[ûÜô‚ ™èëXP§x÷º|æÐtî#)Š@zJž$ü.{%™ï¨3¹+n^M­jP/ËKY…¡­Y ´sÎœ‰—]U`r€Vë"˜ðh¶œ‰pøQÙ—pœ4+¨M¹¤åÇNFó $)Œ_Âêl#NQÓ<õÅ% h_™úŒ1øÛ5ã›ZÂìouX×Ò}¨«ˆ =Îéƒ#%T®Fæ‹Iâ)|Ùò½q_–Cfƒ³DÖ9>Uoº![úÖ’4¼bBâP Ò¡´ÌGi¢%00G¨B°À8Š§Ž€v .¢MkäÞÛ£B<ãá|óâø °m<Ïh¤]¥æ7rÙtST"ÛP(aZxdîÍ‹L|µi±î#%spW|S:nˆ=£ˆ.¯:ZúÑ´ólZì&Û‚ t„‡-O‚ ¥qß0<â#$‡è9#)*ï‹@h<b”º¦ïîˆkô ^D±x!Œªìtæé~%óX¬ íçÒciNN^dÑ<1š/iÜÒŠŠpTP¸À3ßšcä}º1GÖI»¹ê‰ní ˆRC™m¾'‘±¹Ÿ hïîTyôæ—2«ÕÃ8³ 0ÂÜÀ¶=NËšô(춶Á£Ï µ\²:ä±Û]LéÖÈo©uŠázãÐÎW4ˆu¨†…ºÎQU÷#)ú¨˜£g@îª#)S‹ÐRÐÆðƒ6\×¼S{éJª\u#)LSÇ›ªrJh¯ŠÛ':ˆH«FÔ|­QXCJÔ¤#$ö½@Ë5CdÄîÕCòucë-7‰=+1¬üέ¹£6zòÐѶ*œÍÜ$ƒ—_^FGJ1œN³Oø’¸¨a6àDº¥Ìî>\Cμ³e«ÎCÔ‹fÈŽŽ‡Ô©iëªQbŠy0ó½ªQ¹ Gć«%ÓL¤°°ñ, ÊÚŒ(œ'8Éúö4q[Û5ÊE—!ASÍ«)Þˆ¼4'Îw‰QðfÊ9~¼x:Ø`ÐQ“³·ˆðÞ-¨‚@®4á#$¶B«n®<åàäpPœ…X˜á¦›¹1Ù}Õ`+CzÔ@¤€RÅt 5:}tÆuQ(zÜ÷Ø·¹ ³ßë8ÙÞ1¶é#%Ï?™‹Ê^PÖâi`Ùd]ÇÛ¤Â×êœuéƒ æŒÇ#$,ÃOq¥Ô-ÂËn7uNŽ¨fàƒÖ#)#%V(ª™1šy5¬žuæb†´AØQ/ãuI:ÉÕMwÓZn@lêx‘ʤí¥ÀR馵Eº´AÛm„ôg†I˜ "Ë8ÅÙÊ#) 8Xí#%OJÃtíïEçÝêó–rÄ÷'…(ZÖñÖ/õìƒÚ© òé–í@„Q»w nyéT[@i|¬ P#%  7yí…ðº«Eq  Ð„y,éžÙÛª¡U£Žxm†RtÞÃ(eŸ7ò¹ U¾¥ÐtÔC~žŽf\õ-u“êtCf&àÌ)«ù}ùôýÿÆ=~Qëú2‘ʃ‹|Î_œ:”j>Œ•Dÿ’Ë'ÛÓÈ|M)©TîÈ"#)V±îpúcé%•¥P*17B£\xÉÄÔ÷è:Y©Æ½0GëɾuŠé¾£°n#$“ø{©­;œç§0Øx0ð‡ÂŽ«Ç@Z#$ÉÙñ¬f¼ù¥E7«ñüד²¾Žl6þÛGáÜ<š„¯¿õ½bÒ•˜^µ›³_c=Ü)DüF(~&Ûm9®Ð4†G'ä/wCŸ~^ÿ˜U`ßCÿ!a@›Õ¶èŒï :Ê¥@"qÃv?ñ3×_wùÀ÷áýÜw}áû}ߪl$þ”?œ(2–#$°@ Ï®pj‹+ëÒ—ü’Š¤§ûgø‡, !Û¢¾hó0‘Ô]áA±(²· À©`ñ¿Ïh1¸ìÐ[?ÔÏå-㮯oeŽÍ ·;s,6ÿTßdÑlí¨~!‹ˆ ä8<º‘…öóí7#)š(&Hl:Û8œ¹‰^®fÔúüo6ñ`§†%#)¦½þä,ΉCébý Ô}ÎðB©Žà#$¼Ÿöò[§Xx5ÌG¬{AØ`ÀÞô{¨9žïoû_C“ó/Öæ€9šCÔ.È®Q_{ƒ¾Üu šYiØ^åÏßwûBù&¦@6ε ±ô` >£RÖBt›c’`dže=kÐ8 þìTûýK¡ÝþnÞìÞœò~„ÂÞ êŸñÕ¢U­úeöãÛtŒŽPKM=¡Î¯@2q#$˜H¯)å86ú ’HFÓ<•^¯d­ÒUÂ#zX@ª#$ ÓÎ(•¤skíþøý~~Êì#?m‹nÝd´ Õ$o—OŠçûï~¥nÃÚÅÌ ü$IŠUW\#)–.û–\>h“Sé4n)jJað+|Á·€¾Ä2†ú°9ÿ¤–­†ž!à†êü¡Ã«÷w=“†Æª-¥ˆ`4¸ÎŒ7qÁ&ÊFü@"äl57+#%aSíE8‰ãá±4æ£]ˆžØ €DþG¨¤4§ÏÊJ;HÉøÄ$/ÓåMW+6ç.I¿«ã¨€zƒ›ÔG@qÑÖÛ°bÐ}¤™ìMv#jüèn;îäk{J‘’ˆøÔ°—Œ PP‚‘.˘#%ïap]¥(ÀBÉÓé-ÀŠsw1¡z#%r$s©V6Gal‰‹9'C :ÊÓ#)àóÖÅü¨h4óŸUx^®RO¯é ÜŸãòðþï/Ê>‚¡,ÿ9PÀ<fÄá—º…D¢†…ŒÂ1¡ÿÈF¯þæóþÀ:觘ÊKïã–™ý_æãùSþÆÕ´‘û„³ÚžÌ%'èÁヰ;ÁcÿRã]÷«Y×#abå{ü·¥˜ö”dRHõpi2¦Žtµ¯ùëËË\u[ï»nѹ·ó£Œ†‹癲ÀÙá0"²HÛ>?rs<i)X<tõò¨¤ªõ·a­êŠQ´$ÓéZ©QvcÝÖ=à —ëÁÊm28{‹wínÃa\æ–'ä1Ô‚(5„N‹_Ÿ· ºÍÐ~©œØïü3>ÅýÝ̳îÔ5½÷òý‡Aˆë=eL¤£>Ü–Ô#)Xš·’Ò “à4žß'C’?ÃøT‡#$ü(R˜þ#ÆåA%S•.¼®zÍ­îu„:”Î&`t”àÿ¢g€hç‘fÌþw‘ÌXôƬ—kçÔÀeî#%J4k«Ïøu¢#%dt’ FpgŒbÝ’K!V.íÝ$’H™^«¼ùû6®(óÙ†8°àصß`ÿ)ë0Þôo5í#%^aÚàêFA„#%Ù=8üLa´è6™.pw;²Í—uK6ÁÄ¢Ì#‡š/à{öú½à]ê4 WûGö"øœ OÝýÛNÙò:žtÉ[L_Á¨4\¿q€cjÃð]þ ñ¶ƒhÉg©Y¿‰÷½^“çºãkÆv²#)„Î Ÿ›TÛ|ƒÞ\IctÒé‰bŧý^ÝûÃ=<g°ò°u:—¤2„´DÕ’¡ásëŒφ¼/º:iŸK´ˆb©?¢Qô-¾Œ¡ÂØKH1±¡ŒM™$Î.r¾x–°RÁ¾(4#$D"ð#%i`øðÛ¸?z$ òï¤Ár"æ\taðVƒ/§éÿgB>pú:{ˆ„J¤„¦Ez:”ÚnO¯CÔD4;#$ñô9·'zÝã#$¬”@D|.aŠ"©£Ç{X¢º4ϵ,ø#%ŒSŒé}öTZR¦·Å‡Ó8«È½²d¶K#%¹²¦šMaQI–$Ž:Ñ’˜1èddh Mž1§'·¸¯´54Œx°>â{f ³É¨…#5ÖçôðY;ƒ'CXpëâ, {^2nfóf!Ž¦OHZéN%ÔÁˆCS9"8P\r!õ¿áéüçÓÔ?ºå»oG×Ú…ÃùþþYÉAkZS?Fl¹®î?oÎ5àÛú~[ßz¯^™)"1‘E@zo‹ª«¬·ý,UÃŽCfù¯ß»Jm”ßb•µš5­oC"z Cˆ*ëœDKº;6ñ™2¸Zi#%8pvd’BI›«mb“3ZÍX\ɨV]YkÞõ­ÊÌ ŒÆMÃN°£#)=<[y¬J2þÜ3a7Ã{Þ:²Æ´ŒÚÛm¯òE Â9L²ãìøƒPYPI$9Àª!¢ ƒÊ€#$ÿ™ïêIƒû¶\9;ø7 çœGär¿âþŸezº-­ÿ3‘žZ"‡Øí#)¶©\ËT’}5{5tˆÄó˼ÉI~Šý붼Bó»ØŸR>ß­4ðàΔ h}„:;í lF,]„$$·|ÔºåvÕõU¼>ó\È?Í”Ät"š†ÒJwÔ["t*»ÕÙ¬$ˆ €r¶QI´|àÉ’tÿ»n5Œäй5ßwu¶ÛmtT¡Û1À‘·¤¦³·DÊùÌËÄ¢}dñrTÒ±ÏJMsá/MÌ¿Ÿº19l<ñIýWêÑ{LjçÓ.O–"lCÈ2PZÅ›Ž—ÚP¸vr 0yò‡8È*Á@A Åî_³]:µ)¹£Sšå¦ÈF©ß?V±Ãá#$ø×ÉöŸ`|ìu7}ÿ»+hôvùzúŽÀ0¿GéTžä~–1‰yrŒlV$õ–»Š÷¸? ïÚ·¸Së"_Úv|3çgŸÈª*T”¥"ˆ§ ›ðÏpSF[¨5º¶È7ÁVÍÝ›è@1ÆRðK:P"b~‡ÈߟK]Á¡wh?Ì‚ßÄ}Q8›þsˆñœ¢½ÄÄ´ f"y–ô–‡òÅ-î†ô.¤$ #p“iáàÉ``È3q°šnãåuoˆèCO €¸YùlႧ¢“+@#$„ ñ·ÝôÏuçò_î+¢[ç³nÑüGÑ¾Û !)†rŠJ =+ÞÊO|\B,À6ô½`)gÏB£Dûv‚y:«Æ/Ú‡žŸëÅ°ùŒ¾R{ÑÜs£§Ô4!‡G¿0ÙrEŒX¬Àæú\#%ú½ÆÓëƒáº‹Óˆ½_¥ùΣäÙTåcÕ?=NÍÉ÷›Ä8@w+ÕNÂ*Q8#À#%Ïb‚L&KFÁûCÂÁ€ ypéê®>óÄ8»š0Fǘó™òÚ´ £ÀŽùÝÄ©kOõöj{{{!` ¤"‘HÈCÚuƒ—ÞYéSúŽkuaܪÃMž:\èC¹9>v†÷‡ 2 RÇ̽<éI2yCoOqUôPú:¹—ûqõ–¾$ÿ-´1Å„ýçé+ô“å>K·­éÑÑDÑ”=áù1»ÝŽ‡_ÓùüO/WÒÜ@Ä.¦¨zTÉ@³òÂ2I$õ€\U<‡Ð·÷fV+›)@H‰çñüâþ “è:‘N¨àl hiÙÐ{(¿ºÇ/¦QÕçh€œÚ¿nfµkr­¬D÷b07½ƒ2eÎ2é/†F>#$0…xý>èì10GúUIX t|C<wÏW~a‘gv}J¯äcì<+¿„¢]âæèà¼àS›€±8†¥ƒ™jºoÀíûŽí‚Ç<Äã!’ÎÄ`"O[tž‡³V¢"R>RQÀɹ ³öÁ.&Õ#ƒ:ë“„K‰825–6ÆwåòqÂ÷rý£ø;_W»ò„™´¶ R–6e8nÝ3Í0”`Ì-u‹r6ÍèE±½„îzLy†çКtpp"˜UÜ?¤ïè™aƒ"H,ŠÈaBH„–½<øs;#)¢JD¢‡éätaéa*´ µ‰bªH’´ÕÛÉ_(>î?YèDð < ÃæÉïµp;7ðœÃR#)ø ö›NÍŒ;ÿ¶o É^jªQ{žÏ™âþÇ×_ŸgKS ·…àÕÜotcz’zä·­?– ñÂÔªhrOòÊÿf«(Wÿ=Å(ÃkyiLÕF9(©t½àÁ ™¦.š‹kEª¥(šG#$×ÃæêëîžsºNÙæµ°>óßGb˜)ɧç¤ÒØ=§ ¹Y*Ö÷vÕU³Xã#)¹Gö&^·rï4|†Ïd¡SØ#ZBu—ßøŽ2p)æ+T(¢ Pˆµ>"w§é«\‚(m¸gZ¢ »ÁŠ#%Å|‰À.ªÏTì€Ðä¸K‚ýO51ô/™Þ+à6R4xènã7ôò€Xö—,,X!ê(->Â/ò1Ÿ\­Z-¡@ò3”{¼yòþ"¡ü_Í7îŸ:=Œñ³ ,Ϲ‘¿ªoBaMK•àfšÞa—Š1+&¡"$®‡j p@CPî“öÄ„Ilƒ#$Ê«s2”¥õfÞèbǵîJë=ëhµ~”® )G”Õ(DrT#̇㊢9¦ CF¥¯ÐvàyìËÚ‡™þQüþ9dRdƒÀ‘’H¬6ªÒÆÓ}¨lÕ<áøD§nóE25#)>TjY((9‘'X´ƒ!ÏûŸÑÀ:<û¤RÝ/µyXµê:!…¡çöÒ%ò´éª«) à}w‰Tj–EdEE‘dJfQ¦úû;¹­zÞ:­ÈÍ*Ce²·uç™u©åÕKD´‚ÈÈÄoNAåôz>œ¯ð‚oQ%лëòž`õ¾Þµ#)#)#%ëãpÏÚÌ EùÉ#$–½'¸€X2W“ÀjlâÚaÖm~Í«!ú¡CSj"˜B Š#$PL,àÜáRŽ#)CžÓ4,D çG,-d'ƒx‡š¨ºîäìÞp“ÍŽþx×^UÐ/Á~ Z[!Ú4“fäêÜŸž}TRN5 7vI‡:ŽšUÚpÊ:ˆóûwnìˆVñèh9óGc–sÇÓ;mÓoªÛ †Ü‘.0#%¦!Ài» g1‡šÚ{.#Ò'—š\%tÀ•Lú#)à–€DøþW•\.[ºjŠEQE¿…`©þ0?‡Ö|Ò¸ª©¾ÎX÷q}šì!ZÍ|Á½ów6±ç©PÿÌôclþ´MŸ`´*ÒÓ0ÃL˜a© ‘Ð9†õ(õ,’¬’HúÜûX?N#%áëè¶ð4 4µ€jbA Ì©hxÆÙf"ŸI¿‰ðãE!ò`Ciš:1HèQ±ÅÅ åÓüœdDèÙ±H*àš`0Š|ÀPø;=>ÏÄ~þGQy0œ³~Ôy‡z¡ Ã¯§oLJýÔQÜBØ0CóÌN¾_.å}|ÿ®eÆ”ñl+¤~îVÈæñŠÈÆ()(îOS `Á•Àd‘a¯®èÙ¡¸ÃgsÈBø—Â}gÝÿ]} Ú±þD³Ñá•#)ÞÌêû~¼vsýâTþ¯©òÔΰôÊk‘#%üêi’„e ù”ª´U£²¶ˆ‰¨@ÒBæÆgù5=#>úÐìPOg–K³V0\###T}Œ(æ[îP´Æ¸“‡¨H“‰.b©B €¸K‡LQÕò#);»_Ìíȉ@çЫH¥,A ‹€Áƒò¸.ØïÌÝ.<Îjäž cù~°±ÙpÖ}0¸rÝÚlÞò#$¦õ;ípp"#%€:ýU’èÁÁA2ÜŽ—QÇ9†/§nƒÒ§0æ!½íÆN;¤²‹pýAÀSP jèð+½77XvÜ1S§#$0óÄ:JåEXw™Œ`ÀQ΂½}h£W6xtú¸B“ß±T(¡œOEØ Ã#$#)ÔXÈOçÚâï×üþÜjd­èÞöÄú—m™ífÚÊ韵òÿ¥šâ“GU/±ˆü˜Iâ:J@€Ø¯Çéµé$U$M()‡jC&Ó×JÀ£‰Î{Q#)Ø›—óÎÇõ³œN«0_žÚ¨Î`U‚*dýi(®Sòª--lm,L»XWW#%òû;„sª*ã°wö§ÀËS7Þ3JxqÑÿ³°ÚbõûE]§*æ¿&ιB§ W‹Ts<Àû{Df“Z]OBd+î(; ½xóâìDé‚È° ²8%vÛx„ôÓý>¬jI&v!Þ¥jpî#%æåÏók{p´É6^@ä¨gCóSQ3;W‘½¸Ò0!2#%^6‚)a€ÂJG‘¾ôWß èCÁä¡×ÙĜгÐüBæLŠB«Bª†ÖKš9éãÔëÔ{§ŸÈÝEÚS(G™ùBlÀ&¸ƒÁQõº!FéÔž9Û»‚¦PÞvŒÈ|h¹Bù‚ÿa*2<~Äkd‹¹{`€¾¼LMÎZ„›b€~Dû~‰Ùçówö–œñ?¹¡nš¾Ó£o¯ûÄ‚"ʪ#%•BÐR8¼‹ª <{#h`´OËísã؇_,øúÙîWà×é#)Ÿ…J‡¿é­˜ÓFÖ Îh؆ûóe}ߢÀû©9F#)fƒ™ÌîðfÏ?ó~›4ìë fñ`9Ènúªgêí¶ÿmYkíÙ·ivýĈð§>⦨¤ˆ€MÐ!ivB ¨€€H7@h#%‡3#%z$GäÊœ}ˆà…˜oZ ð$i–££ ˜ÂÀXôPŠR|ñ÷w{ƒ·›0ÃëCh£®##—‚,`²#ûúDàêê‹ÚG’óyv¦=Å@Yz„ÄKAP ÓÌtœ½äÐT6üß“cqôæ6O@èSÈq¯,pž2‰Æ-Žƒ \«8 E1X?éÌÄŸx=FÂÞVb‚ȶ.{D‰¹¢v‘§°9.ÚHk) Ø0–š…~>ÿŒú#­ÿ=çÛÙ€V˜@b·Î]×o:⇊ñwkhߟ#)i™õÝè1’d%ˆ>§ÄØCxÞÛçK4ñn0×#ý¦te8îg#†µ‹Ár”Cű¡xÉèñ»èÜcë`•íÍ<£oW×VHŒØI,×Vΰ `«Œ#)5ó~-sñõË–wiz§ž^DX’Ê sl«ÙãèD<¥uÚÃ齧?oê´"{Ã5ô ÅÈ ª¿:X"˜{“ºzϡωÄ@ÃãÍWß×í¸¼ˆbŽßŠSpý¾z;½|JE”B ¥wý˜êN#$y3ƒòðI‰"—·ò߉ý§]βs*íñDG­[j"‘‰cÇk®3~ݼÝÞZ¿ßVòšÜ_êOì౎@á‰r`*³¼ŽÕǶ¦ç & Ö#%?~³óœD÷+mQ±Ezõy„ëºWÇv™K}o`"‡âI¹˜|‹óÿˆŸÛŽr¼ùøT%4¢ÔóþŒ(ù–ãó/Ý7OtöÑ*£åG<š¶×i&ç)È&䳑ô9{žÃ§ÏÆò~ÉBy XK}2<<?œ10÷cþˆÔn†˜öö@ž™Fú¹ðj`sûz5\Ÿm4b~ˆHÃì{Anw˜ôo/v½ó¢¯ûu:=E5€Hg‘PÊ:qü<mìfÏåÛàn„š*›oaØúáì#%:è/“NûŒÄ=°,ifüËáHSA@ÒThž…•'/aP±@U„XAØYÚ°ë>aAÙü-³ú¡Ôll#$Ò%ˆ»½ý\KäHâG¯ð? }Ùv}æ—k„3®Ìí`ÓšÖF]€”‹h„ !7=g¬w=Èn B XQá¶û¢»’²v?}îK¯^”Æñåò€ä9æþ}*?¯O9rõæ®[âÿ+•©ãørCNÀÿyCÆ3ú¡#)àÑÜÐALDz™¼ç]3-“ÊgyånØFÞVX2h¬'à2dA`¤À!Q2¶Âjjú‰˜æ‡q]*j…‚t ðÔÂÒTÌRȲ§šØ&ÔþóäÍ Ô„(ÿçŸÐ ’¦¶c¯aj1ÿH~Í¡f(-4ùê"bâMr“ANìW{¢Úi«Vn#%èÙŠ¾á‡hF {j#%÷D™q+Ô´çhUˆàÞ Ä€ße(eÇÌĺ^TÀ¦~®“Oñ½ßù|µ®lY( {2¾"£Rñ¯àŸ† )þ“¤ðU+%E÷¸EüòñPÄÈæI:ÿ´i3 ÈýŸ£•tWþ|ÃÍë¡ù};3˳ž¹Ó§^X0¸þEA¡Ih²ZKH³N-N½l‡ûû”ušùßïþ¥ŽpX>ïOÿ™¿ØyömD~ÛÌâ"¾TY.îËšï1òÇ{ë×Ú:yT{,eÃMÙ"bŠˆD!N_ÍÈ"oñó!N¹ùsÚü„y£Q‘AX¤,Ć9ý.)B‘Ôè삾×%£¥“Å@¥Rð#$ œ0¼*5#$@åì'ŸfÁH“5BmA$´‚Ÿ¯ƒœ`‘UãÖðž$Zä=Î#)$»ù@‚ÃÌ¡”-Õ»R¨$#)hî‚&ý¬ºsR?³œÁàg#$Jª¤6 @ÊÄxèF#)GŽú¡W&IçýŸÈìÁñëäw$!¡Í·þc¨¤\²L¹pzï´´Ÿ$àlCÀ¾ñÁÃG³ïƒ©·´êâ=ÆÑÃSQ—ä_™1›¬äohü,£ öÏñã<5:ý°Jüµ&/£’ÂKDÖÖ?bì&Æ8g:µ‚¼<(NrÃ{)t¾Á5úÉï..S­b<‡Q´¼>\‚€áwAÈ¥r õ²`vN¶?ÝÍþ”ÿ5ñ5Üç·l<ç’[Ídm¢†k$éÔþ{ ¢á•bC¬ ê…­nÕ-eòt×½àŠ(›Þˆ‚p ÐFÙ¯Çúõú1_lþåéz…è/ø^§ý?ïO`«ËBòþ7f d#$àç²'Ä+T@~_Ë¿20A/ÓZ¨PínÀ‚ª9Cm?}ñó¾o·ÁåÀ9Ñáøªô>ëµQØH>ÀÀ"Ü]4¸Î¯H±µm䜅ð{³´ QShr¨Ueæ#%v1m£Q£ g à>»„:F+¨ÌÖ'ÉÆöÆÛ'Ðïaņ~Vtš.(Fý±#%÷\£ü±Æïcî3¨j|jÏ%Ï£å#$pÜ((¦„A¥äøÆãÚ\îtùϧ£ÚêÔz›¸éx‰àŽ1¨¾j—ÁâZî£Þßß!7Fí¶° NÕ;öuŸ‚ø{7‹ —CT.­”9XðÐu¾úèÐ-Wûä‡9@’ßIÌ®¨Ê/„t_ÙÿµÚ(›åd35²––ñMêopvGW=töžŸŽ~ÓÁ9GõÕù>³´Ì?ô^áÇ«·²Ê}í wóvñËÞMÞsXVÂ5&ýöü2Äk·Þõ28éœLðÑÑ{ïYùu95·¬lÞS¶ ­L#%%ÅE…ÁnhDSÞÑÖpB“¢¹;@:Óf#$x)|8Ú=±q}žDk˜ë8~ò£½ô_t›'Åëi¤X´Ü©l Ïa‘9A¹vT¨H¾»éä^ò&¯Æ±ã®ûÝ&ðà9;¹ˆmÓBåÜÙÛe‰êƒÄë± ?8 jÛ2òÛYµ©oŠ½“ýWäî×Þ;¦š’¥š*fˆ*ÀA#œhÌñN:rÖh½k–q‰F‰g§KØúòýÓÇb ë‹ìyþˆ‡ò~¿ËØ]¤</^Rµ|ëÓþ#%LF>'û=Þ±ï?W×/Ž½¨è21Š´ôä¯a#%nÏ¥T Ì3«„º]¥„ZÏÕ€g馸хF5Ef)‹Ñ#)*p¦ù·\ ÇÜŽ9â1³k;\¾ú¢tŠÃº'óg#)J·ÿ^úË箇ǩôæóéwqµlê4-u«Ò…qõÜõ§oöïÝÉç<øŒçËÖÞ3RãyïÛÀÅ×rcÁ‚£~ÈÑO{ùñÓatÇúÕÊ7ôÌ i ¤?MÒ^·N©füM=;k¦š†ì§ZO‰QJ##)1£ƒ]Ç@ŸüïP>Tú?jrôB¾ª‘ßÝäfˆ‹½\l´Õ瑱æ"ã÷jð›iã!±y<„C™QýɼÒôßYŒø|”wÆGýÍÇ3@iîÆ39dx4—çðO™˜1£¦’†Akéù?jƒÏçÒc~¬yAi!˜tÇ€å ©D3Š›'““õïßnËØÃz"ö71·\MÍKt²=þxGÌ}ÙË8õ5øâó0˜ÒД 7ré½³2cœ§.%麗 @ç#$ÊvÁþDІ5×´>4ÇQèòÿû“NM´@yÔJ w=Ú`:  Ž%xÛ&Ù¿•¯X”WËôÇ;òktÏ:yĶ5d#%ÄMRôÜó³–ZçšT,ª&€«I$ý9¯¥k ÔIP›w"‰ÄpšH›•H™Ûs#%•ÍÉ-¼¤9ÊÃâä˜z#%z"+e¨Á.·•éK{fý Pgõ±(›,þ°ýïòëb¦¡êX¢Ì;O)##òþ?/ôG½ñŸgèðé¿ó×lø»Bš…y¿ÙíKpŸè›[<Bgyü±¦’*¡Ïû¿Áïñ:ï±°öˆÒØaôJkõýoÆi³"ŠdÊžªOͳöw\þŸÜ>Gõÿ7øŸ0ÜCûËΖƒ†Ì#)òªª°ÿQç`]L ÷ÿhÂÆÅÛ@oÕØ›bq+vòuâs4#%¼Ïñ·pô»Ù? (»s{Ä¢4ÒR$`FÚòOòh\nÛK†Ñè:w=o$¢OT ôlu:Ü¡„Á°Áf³Õb6I.CÑy‡³1G¶I`ÈtÑÜók$à]K¦;kyTUvI·¨º[ŒíÎppå{žƒžñäçÑ~· è½piF2H`ôDAFF ây…Ðà¶gö›çë6ôˆª±ƒÒ©ZªUqÔ†Àu(2íäg&@N0Ï{ôòdi†7l% Äõ~´ýUuþÄ)ÀÁ,Ø”a#$Ã-î;gáåb õ”stëE½ò‡M æZNþePž£òîú†¸aζÖÒ_Ž¸]}ƒ>x¥P‰ªœY#¬éuÉÀa™ˆ0"PPS€á)¤– ÄÐŒF"ª4aF Ì4Xpl¾à2ŽŠg†ì ãí Ü Ì+¬Bö¢Ò›Kì»×À¹±{w»ˆ Ëh3ËŒ†OFU R÷Ô²’T p³ ÌÌG2mwU@ëP¨O—_{÷iËî$)Ñ—OªŠ—»âæµÒÖŸœ#6lñÆït~wuy©c•]zÁÎve@À‘àDÐÉHMЪ¨Z4d©‘bŒ#)³±RjE`Ò2!´Á ó¢†\f§¬#)½‡Ò@)ª#%HBÍU$+ù_ãÿ3âß•™ ´Q~þùºk+",#)ÕQAøQ,¤‡ô;ê$øHv‡¹TA*îÛ³éwÁ‘½ý«ùØöE{s¯sX‹˜ãûz— ø@sôéÐÕV+åÀÖ?ཥŸ ì˜T’àvIà§"ý£:Z6v9jHÆÚDÁ‡+!#ö¯v+mXí⧙uþeßâÊc^Á™)6™®Õ|i%A±ºIÈÄ8#%ªÉðöÖq‡wØZ^¬Ú1Aµ_q=ñ’“Ð%0a„Cñ)ö˜¦I Ö1ˆ1íñãÝmÞÁáí܆Ûør««é ÌÆq)€Øã›Û»mØ.~ãm‚­¢wqaEyJÚ.¬ð3d*Äì,(Ô_Äz¯Bíu4ì⣤ŸÆ¿ÖÈ“$¹‚G~˜C!L,²o!r爐u‹@3sÅ.sw&9)(3®ï#)$]G.ÎYàå4UîHc)Œ$®I©“Íë(è47„¹¹S>¬§mZÕ_+_ƳÏzëw—Èû£Ë$qã9iNŽŸ=tõ×g<Žm¼µf¦I6ÏKÞ¸|ÝAÊÜV[:ÞfqpeãAÈ.´ƒé;ÀädâÚñÒu;öèNí(âˆl{÷màó#%'.R:.ýO˜pi°ÖA¹þŒŽTÏ‚ør†É‘Z†† ž;˯[‘±…„ÎF'Aw!CßüµM;}^Í ºv‡Ì¢uƒÒb–2~8#$#PîTߧ‡^Ý|ý{òá̪(ÏapA* ¢=è––ßÏ^š6¸µ.ú0ÃÎbmè¥U6ä®^.i'¢é.=36ýàÙ õÙH0˜u¸Î&sZv,A"–»œ ° ” ŠYzøÇP‰#%œàEY#$ÅòÚlé2i}"p;•Ã‘Íö:œa¶œ[%›Cß„jŒ+°Ü—7ÙG"&É8#$ j¿aäóó‰;ÐÔØó ”Dó8ÍØL«¿[mâñŒb¤;r°QˆI4Òd°”É"Ï6ó#%±çNž!ÎM'¦3z÷?›0Ì{½½Î¹#¿Ü°y±Cšöa“â p(Tv:n.¤xðÆ {ÎäQdé… J#)•Ì5àÌ­6 »&€qÓõÕEv(ÜS¥ëpSi6›±ãžöêÆíÉ íà¥ÆðŠnIjìxnJlŽ§!R„;SØUÒPÌÍÎ åP=_a±‰ŽÂÄj#% g~¤­®q$wtoTÔ”ØÑåŽ}·ÆôcÛ*ö7B”B$$Z€›¢¸å‡‹Í`ã1É…UmÊe¥ÖéÈÁA‘r‡¿xÄ„ëL#$Ø©‰:#$B@`ÁVXy£¬G"PRA`k4ƶK³.ç„ä±±¦ª5"·QÆòƒccÝõÞo¼û-ʹ܉•Œ™ ÀÅQ¤â­T IÌ£ÌÏNØrÑ,\à@&Ø+ǯ53¢!ÚÌÄ©™—›™™™clÌŠ¬Ì™’J±Û3Ñ/#¢þ­´Ïvt‚8°ÍßV\务 ŒPRAPÀaì‘´ãyÙÁ­-?‡¦ý“VW›<1¸æ½DÆO(£-Ü[žß„-±Ê~yÕQLÓ®²Ñ0DqR±Š.yRÀ¢=.½4õ\ô––[®‹¢s[¡¡iXïÑ<fÁ¬M“32Éð±D‚À˜B™Â8[# ;Ž+=ZÍÇ<0ƒŽ†F™:õBP sÜ®Ýù4¨§ÈBî1bÈ”µI.©lªª¨(ƒgM&þÃßÆôC:íT%{V¤jQaF ÅÄ,Y™ÒKb_NiÖ˧Çn$|n–›|σ=j©°*–4˧p†S54Û‡q˜ŽSE((ƒlcü¶»#) ÿÒ#)!ÎtœuEEZ8t+ÌN[›*„#áÁòÝs.Ïóß´Ô#%@#%#)“½Ø8…Oq~^‘È´Ói!Ç¥¤GÆf±xF )1õtû—¤¶| ׫véǼ'ö¼¶Äç¯Ñ@NäÇ@®„Ø”^¹nj;ù \«•ù·ÂkBŠeƒšÚÂ1Ñ*lˆBd>õª5fɺc}´âo#%o! ¦ä”Ûˆ”ÙàæÖ‰¬@ÚMƒGnÖ9¶<²åÈe‹›‚dս‰î6) ¹ÁF”Q™ÆIÖ Ñ¥£ÅNKÍ£SÁr„”ç¶ì0m#%^ïfPÂg?äý;íì8ˆTB2Ql;DÉ‚!’ä•…öÒt:*“"è‡<3˜)#$™!鹓‰,¶B 2Ì„‚ c M>¶ çi(<¹•#çM˜C—-M5*¤Òp!×CŒ‹©Ö¦u#%lf‰ÛÞJcX_è~¦GÉ4Ï…ÕÍÂ]7ÙfÖLƒBÒ=À1ݱ‡ð ë™6Ÿ(šw‡–#$¤T&#%õJ8^mÜL÷3tLSPbã3Õ©Ø5Æ"LÜÏ D#űNÊ”$Wêm£H)&»`5Æ­!œgdÜ5Øß,+³ˆŸC•i7¦(äÁš3M¦4妵«Ÿr-óãØꌨÁ¡³ ÒòúOsÛ#8y…pAŽ»Jwx¿UÐÐàvì#$ÆHñD‹Te%’ÆÑ4Ùªf$ß3‘‘.ñ)1Ð8É ›œŒ<A‰í:+‘M}™-oÎF¼³@ÞG¨¤·´·=(ƒ%h4Íä o ÙÆkK€äåÑ#%å#)¸*.iÒg°©(,—}9¡Õß,¤|$›coF@/_\l".íÉ_ŸÅ&Cx5tkB.»Ê\÷ûvhWWÖ:5Ç/*ÐÚ’ñ+ùø=õ’q>^2åÌÌF†˜C¿ ÀÆ=C¹¯uÐH 7U’MŒÒÛ¶âT#ÎX ($ý=(Ý‘ö˜1önS^@Èw'Š)õàW«Ð£)«0i)ÅW¹6³m´ÌâÂiŸô4dXjœ Þÿ<0òN~¸£Ÿƒé»¶Ét¨Ž2ò.„èGØEuÿYHBû<cóÑ>–63­ßüèÿqŒdGu‡f3Öø®+Ôõ>Þvn/’ÿÄúcx[­×Ìj¼®¦äÕ«#%ýÙìAé‚…¤¡íól #%/=7wz5…Ëƈ¶#%ár#)XŒ,Ù«`¾´$ÞüÆÃää â#õ@ð QR ¨4Ç”ðàžþâùbŸŸÕ‹1™þ¸}ÿò3ýóòÚ¬Íÿ6{¦¦¹Vï7ÈæESÒT„$mûÀÚª~Å=›]¦h³6H2’#)Ê:úüÝÃÚ<éI#%Ÿ‘Aÿe›‘}G0sæcæ @!#¤LK^wQ&©¦l¥ ˆ¼¹ÐâÂÛ€Ò0€“¡^´SDŸ›ô÷Åï6Ú-ŠÏº—#iQU/×e·Õeööqå !Õ#$¹ØÉ K<âá•è(ï°‡ê>Õ?¢H—`*PÔ#$QÝ”¨“ÈwµÒmŽVYÜOIê²°ÿy$ÓkUDàt‡‚x!LéªLC̯ÙÊH„"F1lK E´WLP÷æyˆH!$'Ý>éršåŒT°"f®ªE@7 ÖÌ@;‘CÓHm¨@„"âk$ Ò¾ý@À*&S,úæÔ£Y!"ZИ¼ó¼ÚdFQ¼µô*¡X‰ ìÅ’i+æj‘ CH3 µ²(Ý#%zûNñ•‰ûì}a‰¬U56o“«‘´’'#ªÖÑ~vÅ]~%Å´R$@èA€ Èé eSí§Ó 2cSÜB¡‚ˆun%"š#$hRÆ9iet2w…[NUÜUÎÜzE rãÇ ì?ˆEóQ2 C¾#$°FçºçE¼DU$@$ Å ‘GÒb;Ho]·äUUýªÚ¬mXªª5¬ÒAh‹‰F#8q~€›’Iè·çQSXDáý¯4Cí‘#%1×m(þÀVVÚåâ’Øj°ÖÒ0h2#$Â#$Æ–G¨b%Jj7øÓ^ȼW¥”’E½îÞ=kr½›{.\Ì5ÝÚI/.î\®kðï<ÛÅÍÒ9ÑÝ\ÜÒVWuŽI>¹ÖKÎC¯kÅÒÐÔ¥Oøsà@˜5" p¯÷NB1`«$BH–,!ïz—°ÀÀH¨{&(\3þYC`#)7t¬:ˆB@’3ˆxN·hø^OO¥þ,>úÛ*ŠŠçŽ¥!Õ#)%F±7ð:îj£Ç=­1c-¤‡Äß7 àü ®™[8V:q.ÂWã€ãššEã$¯Ú,#)ˆb$°|^"„l°Ùþÿ‘kàŸ.MßÝOÑS #$H©œD‹'l%b( ÁŒP"#)GoÃCD™ìâ=>ÛòÝ€ è•ý¥S#¹«5•ç•|å½MLž¾ÿrI¨âðd²q`)N)*çP$ÙÉ®°.Ô¤™"¡$r(im ÷R¦÷3šXR\l“Ëò±UÀ‰ z l©¿‹u.ðþ¬=T~ã –ý!Cµ³û,‡ÕýóžÝ)è§è8Bk\†S\ý_3ku'°û<b~!a·q© ¶­V×}í‚]{‚ýdëßO.× !ó.®jübŠ=îã³.=ß!mô|OpÞÓ‘W'­·~ÙßÃlx'—Så>[o“¬(qôŒþ9˜‘ÛlÌýºBŠ›bsYQ}'Ý~^ŸšˆBUJ©E'_o=ÉÌïYGB ªyé3¥ñn(ó‰  ÐÌQöIøƒ 3!d/E¾qN!;#%ZaØÊ.©VOBOuåÔQŒ…†Ÿª'Ï%Dm‰°eüéÝV³K°ªâ”0‚¦ÿ#%øߟÃÚvý‘²Ê©Q„U2»àMÁáÖ”#%E>ø\.¶1‘`#¶#%m4µŒ’¥[‹M¦ªÌi¶MJتMVThS2­K[Mµ±ç8$œ'Æq·Í*NPá±ÄMñRE€##"$ˆ/G´dFȾ|) €Eœ=àÉ´è[øjâÇk†@(3mQú"pÈU€ðÐËG8“21¡`Êôƒx‚Ø#)²Ê…û¢¨`¬X²1Lãxi ù=¡}²èI)lHÍ䆲‡µ,†ÑÍÞña¹¡¤£"Ð4†´¬À_%a™1&@`˜ªê±Tv*ºh @¯DÐÝtÊ lšUQ mi"ÛE­8±Ä Q5/åŒFO‡rvÀ¾œ ‚UR›tÙ¶˜Ê€My#$X›=úq‚X¤ m¾þ\ÕJfÛ\Û›%r×e3bÉR`¨¨¢´#P© "²/³Þ÷ʾ2DJ€ãXAd‘ÁQÐÚp|zFÖÙä}>¼-šhÛ-!‰ƒ…Â&Ïr+ÑÑ¡a<ž‰"kÄî­NÛ±I?,¤‹ÞèA 9ÙO×Ýþï³çýÿ‡ŸüÿêÙ² ‡žžr½OˆˆÉ ;¼Ëðe⌠L¦*¤ 09FˆŠweB0cñ4B!E0*!…_5S¡ç6á{î;|ùXÅ\ÜšD´#$Ù?ÑdògÑ•SýPùؾÐÙþûTc ~Hx=˜ „¶Þ.jî]Xcî©¿ê¤èçÚWo8É?w03‚ˆ+PT2ãë6|¨% CÕËýùªùŽôêmÜBœÃÛt%(j§eódùµ#%Ou‚ *}–À©9,˜¼ç†yñ tœ&»Èƒ!#%F‰vÆ ·›É9žþ“£ì£¬ˆìÜP"9Î#)À"üÜnãÀj#)×búí‘þ«5&fÌ#nç7§Ò{7¿t'xC±¡Ý›s{é¡é¶{ñ,Ÿ~gSÀ¬4ù8|^+s×÷åÈUQx< ƒò–¤aôwȇ´ùÓ§„ÉXæÞ]û¸¥Ç?'ï§Ǥ†Ç–™¾Ýþd¹Wçþ98ù#$ö IÇËÄ#%`x ¤änÓž!Ä2!f ï:¡`Te0ÚS?$¡q}ç6¹½aÏ·&·±9¶û<i#%¡æV˜:gqNJ¤ôAÃF+úfîÌgTÀÉ#)r2"08O$ ñ‘0±Å¾&6€g·u‹7êCÄ€È+#$ˆ°¤¨¨zGÄ<hï#$N×Ú‚ç’êSÍ#$#%™^0X€ˆÝ¿gÙ°h ‚¹>Ñ÷l|1$QJªŠ…]—è•uGÝÐñ¿˜¤F æTJ¡`,‚‹;ýÿ¾PÌå jTV 'ŽH«¨<:üº8ò˜SŽTØí•°¿ZCÏA"éŒ`}“WÙ `ƒ‡œˆöï¦Úâ@Ø#%ÅÎlÜÌÃ>ph¡E‹Íd( >@áôY2tz<ý•=µú!Ðu=þ•<w‹)½Vcðçø/½Éâèˆr(Ý—ÂÇZº«%*¦@èWÌTyïÂÚ“¥fÐArÚ¯í†í¤Þµ¹ÌC™DÏŸ3Ñxßù¼”aõî/o„Føçcmañ¿‡ôf6+¥þ#%5Òáߢ`âõ¬G­¸éÚ».ž8ëµÏ+‡ßy/¶y1в÷}šFÝm’¡6%Ê;pûgƹë]øÞzmiQ×éí1geÙFMØÊÏKê.½ùãÛRØnyÇ2@ôAțĶ/¦ç[:òm¨4jáÈ/1ñØÕÜlØÀ·é‹cUnù÷ÁI€X+«vPé±f<{– 4)Ø‹HÊ€¤õ#).ƒx¦÷36Pž|Ò›¥Ôx6/•ˆ`Qèhø|19°ëÓyõÜb‚ƒŽ§œ³hÓ[ûŸs{¼Il0ršÖþN8»uÐ2æ:H!Ü£sk!Sâ/´LÙÍóˆ™J ©óX,ø¬ËSRªƒ¸ÐJ»2ë~°‰z'8uÿ-xÛ¨U0ňô?9ºõXlK£<-Æ;ˆHBºï‘³† ¶ÏÕd?¢tDò¾C‘­ß¸†Ã1]Ä|<$kfœ¶lÑrú8íèí¤ê/@_”"ÍÞ\C6Ãr<ö¡ªâtj|=‘~&@8ɱ»uèÝl¥í}͹± AÈRfBèš„ÝÒÉØÖeÙÆÈpÙ½<v7Â9ï©i>½ÆË7åˆ7s¯e[÷9èy*²ƒ&ç%:ò"ÕT ±ˆÄaììñ9mˆ&1,Í¿;¿Dc«T£’Ê¥SÙXžïo×SÐõ"€´zøodÉ‘º˜`•èêdšž9ö½k„71лȘã$–Û|Æ„Ì0²Ž;v¢r]<½õô/[hßøËe0‡±ò÷oÙÚU>œNʾgžúü#)×8ÏÙd ÓÙ¢¤d¡Ê‡)ZRH}Mê©©ôxò‰ÞmÔ±hm:qáÓNJ½JéËàÒï`8®ÅËŽ¹²«ÂÈ#%‡@ý¾›T 2)§Ë†>ž­ËÏ*‰ñ¨uzñk]ʉÈÞ꘽Œè”Á/#j )HS°¥6KWM»'uu,Ñ4[SJ×oÍç-ÜÝw]kÅÊá ®XŠÆÔ,U§A#% ‚QDEÔáÖÝĈตš—ݘát¸¨¥ÂE`‰dsn°ÃjH$‘,„a$"$`Hˆ’&×úgb;Ãóò.ER#™à±dÍ(7M‚´æ·‚ª$Úú¶Ð»A· _—®”‹0#%¤¿BºmDb¾(ª®ËT°ë°RÙ”¡Œ¡î“€!î›çä0;¨ù]ö·L‚éà‡ß$R@AÛœ›c!Fjd °¤“vÖ Ó%šy¤ÑíJ·vÃɸF4ð‚òaZîBqÑjÛ Ão¢Št|kK•#³m÷­{Pivê&fA²¿Vp4À§TKL^À*¯¡çÇ£>‚w0N(?Ÿ't‡é^útU„»¥`%Ê#)  ¢!È”D¤)P9Œ²#aŠ²R[ H%…!cænÒW:¤ÌS¼‡aõ <&_#$5×µø¯Ç2±¢ÜÕcUÊÑ«õ%¼E 5H‡kLB‘1üh¿ŽâzëÀo$„Ç!×:ùë KÚ›>K?[uUìîzpª—äÉ{p >áÞu‹#$«—/¨·‰øâ‡'…¹2ÒÓ-5‚ç–ýÇÄAñChi¡%óqè)çÂòÑJý¾â–7"<ÃÒÈþ $—b±áäA²@'ù^¤ÔÓ3e#>ðÍj‘ăs&æ…[ä‰L~çýû ÃÖa–L¹ôûü»N}/kñ‚2Üa±Tqº3¦À*ë#$Y…TÔŽP¡=öË‘Õ ‰%bÄPH¡Õ(DY9žS¤uW­_+hwtÜ£PÎú½ùH@bzRÖš”’l†ú…SXžbZ‹ü#% !·[*®æ‚eU¸ïÐœì÷' ÏJÛ‰Àá[ºj‚zÔ¥ÏhÎËOi)œ>̾TLNÀ Ýå nJÒ5'º8 _;ÊšËmËÂm£Ó»Lœ™ÓñÇl2Ãu(8“Ÿƒƒ)$’¨>›xLÄÖõx2#$Æ»;"Öá „Ú]ÃeŸB ÐØ]B FÐ/×Ä@l#¤ØT&Áì#%@p Í(Îós¹,Ô#%FAè@P€×D$%Î^’à ƒÁ K dN/ó¹½ÙJý™ñ¡Ë3Á#%Â%ÂL0Êåy“+H½B¥E@¨ŠÔ]zJÉMAàÁm#)ÜBÖ#8[]-yK­kß|«Çe{2—&(@¸³ÔÒÖˆá="^^8 c$)i/°xÚ\5€ Î)VK+u#I¨†Sa«}ë«­µäšŒ,êR“¦Ë¥AåúùÎx¾Ùá+ßPü0?’$oÑ6Ùƒ&âpl5„ˆèÇ£¾±.¶ŸX‘×#)‰²ôµ3~I½™R0¢„x w'#%\øqO£öžA 2j”ŠJg#%OWe7ÆÄò9S=ÅÜK× lXÛÃL͇½Å6#׈é²D–*·•6r=øà– äcog‡‡«µH¸/'™¿XXyõ‹ex_ÓÂF£N]M‰Rw,~û›×ŽÀÖˆBå æQI$ªhvÏGqýI’Ed ÃE:UN•+aîòú5wÞ  +òrÀ©aÌpN¸9†:„¦%,{"¢é 2ûÎ=âó ’ Ï –)8˜|*^#)c˜>½G;þŒO#%$¦±…Â1$1#%Œ60P?k jF6Ñ’#1à !>á…ÖQœlV³D‚¸`B-Š^š!‹uK®þû=L„!tX•*Øv`%âÁ¦(ê‘Þð9ºó:ù7‹ÌbU ªö«xæVç²@; ‰hLnUjÚ­ ô0`‰ånÐÿ)Çi‰q“HÝT x<´-šºÛ+ÚØ :Rp„žÕX?„ª©°¢d×U’ ^:ÝV­6©f@ç4Â>.dLÄ o›©Ãi7Hí_8àml6ÖQÇÃÇ&ÎùÃ"TcñÉ´f1W"J‚òŘFñ@P²¥tQ÷Ô-ïHn¢6ÿUè‹ý)!åŠè…»mw©åf9 ±†š–:ëYÈ#%ŽÈΊ9V#%6)¤þ͘Œz5 Qb¤"ƒ¥·¾Ï,テ >·C¶{Û^OZÊWׯE f FUíD HÉÚ„`±ªÒý¬Œ’ xݨÁ‰¨ÛYQ²Ŧ‹^üwÆwa}3îœc £)äÀ¬­R ±è§Lli‚Äxp5#k³–$½Z%}J#%Œ_ôoMvçgL·P–+…8—õC=÷n aaÈ™P@zæÄ¥µfs圶ر¶Úä€ÍúSÊ•®ûL¼q¼NQ×;o“ƒ«»#„„»IG¹(¸Ã_ïÚÿC^aœB#%yr†Þ•Y΃N%â–‹´‚Øi‰ I ”Àd"THˆAƒ®áoJÅŽ%‹å— YG!#)(Ò#`7ÀN¶OÁDƒci¥ÈÀ6¥*î>Ì4s8CEb2CMl†¯1„)#$ÈÂj ¹b9L݇Š6RC97¶#)Ç0^Y°Ò‘*%QPM0–†D)„±T2Þõ$(b‘a“ƒVê9vˆÌ¯îƒä›Ëj†‡Hçø™ƒ2J9Ë´$šôûÆ(É­°Ò¯mA3…PNaåcZèL‰¸ÇSŠ)ô‹Ììÿz'˜RBpy?3éO!o4¼;Ha†$9à-9†™ÞkCr™Œ£!W®7óåAÉe†0Xá„—¦ ¡Â#$÷”†¦eœN1½éC Ÿ¦‘8@¶¦®eÅÐ3ažxì¤ß? B:ÿM31þþ¼ÙöĺVõ3Ê"¥¼C @ãT¦fœ;{\æ ]7(áhC;Í´,w%î”'‚JnÙk=æZŒ¾?<7°¸jgËÉ÷>v6Ñð?2sZ'—Ø÷7çÛT­Ì­«tjL;ÀeBÌ]3€úÔÛg\Ë9¦Bú‡ÔbXŽ½7@øCàÞ½¡ uüx8ǘ¯|¼#%H#%Œ@0€ö›>Ž’v£çØgm5,u´PÈe1ÅDÐEƒžK@Lgá凜À EÍÜÁ¹J#%’ës14ÙÛ$‘ÌM4hCJ€#%#)š]u#A`}í;3@Se€&#$JyÌjعPº©˜¥AD7† L S#%ºrn8ÐE ¼Ð+<KŽHÒLíôÖBÎgÁ”c9ÇŽ1eûáä‹$ˆ$^2z3ûiµågš86Mö\žÍT¦òXËÍÅÑÌ¿Úy*#ƒð¸L´VÅNd÷ѤÃ)³¤ÉfeÅe`Îkn§öûb“##$‘PÓ²ÂpÑ<Ôö(Ÿ4Y$! RÑ[~…ÏÜI`m¢ªkÅ·6Õ±­µF­\µº(È‚’Ñ…#%°ù´{<»LæH@Î}C(oDð_QÎô#$6¥” TOÆ,¯G 2³ÄÈóžóŠB#)Q# F„JdÊYµ3L’™4Å&Ø´™P~Û©35i ´Ò¥ ”Ø”)5¦#_onPÉ­&,J%3k4)“)™#2#)4"¨¦%2Ãìî¢#%…#)D‘I2Y@jŒÉ‚Ѳ£E‚)„Q˜ÆLÓÛBeA“0Ë¥Fb#%((HÔÅ4R7ÏË“ÂìíØî¤GÈ™‚m@™¹øÍ­}æê'‡‡Ýž&d?°¦Íì:¥¡*¡)• ñ8yLUdXfbZTt匆§KhÃ~ÛdA0$™E´ô•Ã¡$Æ°wó5½è]æÑD$ü(<ŸÂƒ&íÌÝ…ÂÖî7+âä`³–Šm^»›3´$«”þ×¢8®(N}™˜Ò“÷“­‹Ÿ³çä×Ì/¶åáÃÐ6Øc†µŒt‰%†Àßâ*½ú-¿~E‰Cj4ÙY+J1I´Ë0 A‡3{Ê‹xU/wDS¶SO¹§úÌ<„χŠ¬°øóÂ1IL’¾Xå´ÕIÈ ¶Ë¿fþŠáµ¾Rö:…“Ññ)‡°‡U#,'k=?J||îåüÇ=N‚Á’áT‡:¢Ã+˜_#´1h3•è÷Ù¹uMé—VxSrÔ–0=vâ|[ê^f´BvXmZ¤j„‹D€©#"@0íc­áÓåP NRi§Øà|Všc®.³2¹â×8‡&¡ÓBîïÇDÄb;Æå·ÛÍçl;ôw‡b¥–w³éòÿJ+ÃMœbMhjè(I-·}½zÁ"2¶Æ”°¨"X(EÉQ`»ísn0f'¤f¸½¾š{é·§"—^eÈÖß“}¦½,3O²aÏã}èç6äô½fE‚éA.ˆ(_Žº~šïÂ÷¾nŸ¼'ÞŸ:—Û4TÆ4‡å§0ÜQ^`ÛÉ.„“n&Öƒ]J2š¹~T#)¥=O–ù®H{ß'IB·§!0Èò¿ ŒÛ Cò¯²YÐß2qª¢í §€ÆR{-PZ eµÞçeÝ#%•}Jvìm¼ –Û‘kC߶’ &Ôy‡Jf8#$Ÿ£Ó7Ø@ý=é<Ûy÷7gwB½ÊH C–ï:Ê·Ï£ ŽEã¨Xlì=<B pß.Õ¹Î÷ Xœ¤‘Ú‚»" mña¢ {l¤CÅSÉŠ€:ÀŠÇ¥D±…Á9mÆO6]Nx¦`•§‰R{z¼-è•DªYz#)Œ)¬ÃÒšø3xï#%m³®Í%|v;@È]À’#)Žn¸Œa,å¢ã‚“™ŽÓ»ºxù¾¡˜èajâ;|tíEtëù ÀÕ„ì+©· ò¯óCÔÝ9QúÉ}Õ_uÝžÖÛªƒG×Bi‘'ÖÑGjG ‘ìÌfjVprÕ¡ë£#¯$ŒoS3Z?ŽZ·ªçÛÃ6˸ÞÃ1»Î®™«›†XmœŽ×‚É 0Î&šeXYxqS4µš¥jPÃ1³ a™“¬“0¦Ö¦iš#%=›»Æ¬*Ð9Ç虚%rëÈÛÂÝå0'œ3kUó‚þ;®ü#$"ºÊ‡É ™ŒÕ‹­ñòò%‹"î¦[CÕ“2Ö˜ëµciª[=Ú•ñ»)ÞJÎoIÿaÓÑõ:¦ÊÝ8ƒ½8âáÇqÜ~^¥àÎÑ…ÆÆŒcW´m‚Fg*3#$gõ¸Za™C¶ècP>˜]ªaë}‰eÌTm…“‘0p \±•%¼ÁbQ•¡ó¡‰ÝÙÛO‘¢#%³Á½ ƒ¯0ùm4#%fágDÕ[ê6S’5n°Ò#)qçÆyÒkÕ™wB¬ufB¿+P™ 2h˜µ28Í›{#'[ë‹2úuiã&>8ÎØß@ðc—»lÉAÆgZã5OKK=§ç1Hf2ÒäŠû¹7¸!2é{틇½Î÷*FÁÚYÞ#ÙÕF–®²PâúSc]>Çu)ÔáQÆ€ÂMd}ýcçŸü&ÕÍë}Aßj!àv79ÓŠó‰ÄI•ÎvÁ—yZºÎª3£8¼bº¾jwÕl)$™íÙ¡C¡Í¶ÂªÜßlÞøŠ=5œg-÷ Ûbä‘Åž·’tõx’Ö4äNѨÇ7ÒY,mxHˆYëÄÇVÃeÂ7Š¨ª8þU¶áåêí½baÝävß$éöàÓlg0iŠ3÷q¶ÎíˆÑC툮)á뺔îôg3OÖ)3¦0’jc­Š† )E.äÍ [2„ÖI7;-s•’ZØnuÇXJ4“Òá¡êRºZˆàÓ ª0¡pÃ"õWª^|¨I"ÜßP`QèiªŽZ‡4ÝÌ“X8¥ûåÒê3…‡)¤d+z|Anš¸Šˆ«ÁX9}¢öLZl9”$ –1f5W<s’e¸ÒA\¼E:Ë)‡ŠfxÅ< ^To'a™w´’qIf›lëÑY¶YÊ`¬½F:ÈU ‘ÂãyÞëè¦K•¹µ•±³ÁÆ ¢WèG(å0ë‘Sðk4ä±²”מ¦ÕG8l¸ ØD# ,òCìí %Èíƒ~€âFšw̧]`€ÕÍļ&©·«WseS².k£ÀÍ‹ÉϽåQxâVhlñ]çg6u#%"Æví3Í®L²j6)e§4HlúipXlhyz壜½g)¶.[Mf0ÕÝL#o#%ÞÁä^`êk‹Lò=Bàst±h“4”uÓró„Ãr¦Dm¢.ýkr4Ç-›zÑ‚Pé”tÕ"0;½øÚÌý¹ö*.`WNŒk'ñ÷SÅèqΘŠšt’ EÉ0:UgáoE2¸v¼oO{†Jkqã1¶åÎ2ÃUŒm·ÂsVߧs2Í]7Û‚0•š°¸N$çSlê‘ìfo,Kݸúg:Õc+Ø5¼ˆŒ§’Ó$C×mW³[s&\Øõªcp}´vGC÷™5%oZo4crÙY©hëdöê¼|3Ž¸ÌáFW•¹póÌ©ˆ·ª;Áƶ}h¥„ƒÍYZŠNûTäø‹Ã¢¯Íêéßzc(±i¦,KnéKjh–ÅX#%bìpÍY©€Ë-M¸Ü·Ô´+£ÑIÃ$8ã57V#o‡§ŽRL©²±³8º×cX÷§#-š»Ê马ycÉUc2ÄòL ÝZ™­×[Ñ.¥*b†µJZh=²²Ãv#)sår®_¾@aß ÂΚ¦õ4l®\zϺb5æM‡Mb~!³:¼DJl†ü©vórdž2Q4úA&nÞåÔÎבÝA½•ñÙò3‹u" Ï5/kb¦ÈE9¯#$Åš™©ÊÀÒðÛU¤º9£Q–Nu1hº·¾©-Xlì¦<Æ<¯¼zcg·95§Æ4N" d,ãú’qœ(ÝV¶—jºã³X¡]ëBá$šŽÁnó€Zè…IÉÑó]5¢ú™9 ÖPdI¾èBPR½/KjãuÒ<–ž'Qn Ã»‹G¾ (˜€ðÅɤc†‹å‚‚ïÁ²‘Q±‹Ìá ÌP5ŽÁmÉ·ßEct„6 oàÍÄ'#%ēɇn2Ø[!|¨¤P,È£ŒU™ƒÆ,x€a3Û–šÕ'oJ#%P4y°§ƒÁãH`¹6 ¶H°ÜaF…¶JMª–#)éYf (Yb-f­›0§“I†S[½Õû7Il†WG))"Š—l£ÑPŠ¡Á¹DiÛH”1i¢Ý™­#%åp›)™K¢CÜæø ñ½rdNÏÈàØÔÊä~°au—…Ä.¸¼D‹LiM+ÙÂ&pL*€º2ƒ8ØΣ=s.S6¸²Æ4›N„É©±‡»:ÁçpçžtŒ™} qП”<>ë¹ÒN%q¦ç[´²ã,fuŠÐÆ_g¾y­æÇ9iX–Œbˆd>†jHx!´d}&›NôøY0+4 r÷ëGS[ë}¹YÑ,‚îŠÃ#%5™F°gx9ºšhÌ6u ™Æ3ÀÔã°F¬=Ù0ÄÖÜb(Ó{eb¡ÀŽUEVøEUÉNS!tŠ-œ2±€,|¦Lˆ,›Ažžaµ»·›å¾ŠÆø\Ñ\µâÛÙµsE0ɦ]`RàRS8à)æjI¹ÀäJ†‡#)†€-£‘É8s½>ýq eʱÖ4µ’ÿËPŒP"m4˜ù#-æaqvî­·ˆôHľñ¹ÑéäÚGTF†P‡CT6p–Ä@(Ìá‡#%á‚ hqßyL…àj1Y‰¥ëØÞ@5GÕ‰zX»BVò©HˆurŽ˜dDŒrºIÄé5 N<ʇ@èk©±L/’0âSEK—í5*$Œ`"`Öm5:Qž¼zˆ²‚T–”è)•Ì åÛ•4@›!¦[€fDØZo.˜&ôı#%Ra¡ƒž¨pkU(FÚÐ.H î5êÞ¢äÚ#)»¬8F¦Ð2.:Ža³0s˜:0°h”ŽbebXß{KÔw±˜mšÚ¸72#)fb]ÖÄg8P©,Ôð#$!À¨6weM¬™Œ™«5UýäµÕ«ùJ_â$‰*@17Ñ`&¥)„SÒ” 0ÿ.ŸÖqWêðosˆˆj_›mùî×EXÈÀÚ–©i#%ÇÐ?¼À1$êEu@ Й¶o;k¿­«ñ®”Ö¾¦W[ªìLi1­æ’K@Pt’Tƒ»-/èô†Éêìè~¶±3åNÙT2Ã>”w‰Ëd‡iÁÙG>kŠŒ'7mD‰ qÈ©k”[ŸPï#Slað ·h©b®ÇF⥥͎IiÅÓRk6•£kvÙ°AlÔÀPÖ ÐÒ!2L÷;ýŽ­°[,rCÃp„"ÁŽÌo¯PÏÀ<56–Ðýò€¨¼Ð—8Ér…"H$c¹Núõ¡TVãM†OÙd´ÄNØB $#r""P,f6áæˆÐØ9$ƒ¨—¤0ø{Ñ¡—»‚µ¡Tcç=D¢°ip‡·ÛÞŠb‡pûày@n‡†!Ö+óQUoÛ´H0G‹ HPWwwk³ºî̹ºéqcmÒþ¸Y ø» sQûMO<Ñ˨yãp#$°þ³˜D7I)›PS‚¡½€ñ?F#)"ô#$Â1Žtƒ˜ûˆ¼xõXdâE«PQ€Ž_qí¤R»J=¥Ÿ— 5.þ'ó™#)—TÚâý-…õàlÿYï÷°Ú<ñ0¬&MMvfÕ´Ç}‚ƒÁ’ĦdDìíCi"4š]²…ä|r ÍÁiM^̓\±Äp¤ Ðj$§ AF=#)àØ(ðÖ‘ÊÞѬ'hŽbäÁbF#$Œx~qçË\’‹;@J!¨ÑÚ~ r#$ýäSPù«åñ -[TÈÞIs#SÎzúýå~²Ö¥¡%¬mŠ5hÚlc ±šfT•¤Qd„#%2$B”ÂÑ> »Ô`xçYª|»D·RžÍ½]ëŠb¯èêvÅCéÈáê|ß(% Âè±n6ˆ,–"11Ž³XÞZ V£´‰`v´ B܃æÞ½-¬Âü)ÝE¯­ÚOå»'yw;J{Se2†OÛtZPS#Dµ~@íÓhŒ“¬I³¿—'*ÈVa’`AöÕE3Pj¹3tP[þ#Š‚°ÅŽ´"È£ÜB9zÖ®UÒ·Ö·²õoDm™J´dÆ-™JY±L¸Â´¸fh„hÆ#Ÿ¼ã)\KDˆs›ã#)Ÿž·nÄ#)wªbF0pѪ¦µA’i0`ë†^­a¬pÌÇÞCÓW{Ä´¡‹ž&A7¶¨·š^Î57šL¶íÇÀ».]¡¶A¨ã*¯%;joE+]ÝLÇ%‰Ü\"µ׉£¬†þ„`Kmf 1äÎ"ãÊŽÑ1¤Ò¯`ºD²b+®—ùç½îBx§„NӻĦä0cMŒe`JD˜S ˆ«î#%$ºà]iûbÚÊQXKÀßglrƒLÎ),1Çð€‡¯/*«UZzÄÌÖjOŽ"‰ƒl I&„`Òð&RWáP6šµMêl!y¬êjZÂ’¦kïr0µ´ëíq&¡8'7[‘§ËÛ¥ŒíIðφ%5†ì´Xh4Å›µ7¢±A”2—ª2˜°kh¶––v‡„OðØ%¤äÎØ"WUè™Ôéc=ÎuÁKNl°‡ns׊š5’š–ô`<ppù’2ñ9‹nŸsVZbÓ‹ýøN,‡[1ºmÇ=N $PŽ¦Æ«iS‚4ÙÄÁ™œ,”ïœ åðj.-£D"ehåd9È›U7E4¥šÃZç<+†¸AÆ xÔÔkGk"ju´Ú,ë–r· Ð„ û1A!,aAÑ!#).Ù#eŒBŠ1Û«±†!À#%\ÁK#%#$p[!##)aTÃ#)`¹”@Ì°8_zj– € I HY¹Â36q¹–€žýošŠÐ?Ä@¤ˆ»Åvn .^žÏ=9T%þÜÉŸz¹M8¤Qb{(=GùºPaù ë«#%®yøeCb¾4v6Épì#)ØËíµ¼×†€(ôÈ0‡á­Wœö¦&„³Põ™õ²EÉ $Œ‘Š/$ŠÃýV#$´mdª±jÒjÕ~Ų¤’$!CÜH|âYmq•U–èð™LK‘ùŸ õEJ¾ÃûßT¾œ_¾%’ÂÍZþø6óDëªwŽ«Fö¹”Æ«¹6Mìé§#%gy“LÉ•sS#£*T»§–Z̧XUŠl¦Â&Èd­±v5-YÖ®”¢&†ClC8MÒ.™{¼æmÁ鮊£’ÝJ™“I)Ò˜JQ‡§—jx+~—K\‘¢LSI”QåÃRlˆ›™.‡Ð8¤Føáæ¨D]Ê4c:µ:ßcŒuhÖ꼧¥sù–ÐØ¿ÌäÉÆòmN·äLÌ[űºÁH¤;,+§ÌR)ègC1ÒuĘ•pìÎݵfgiÕ·Šªo|V6Þ¦Ó\$×3’¾fŸl¥9¯¼¾1¶\d“%aÌdž9YàhQ´î›&ßg¬œžk“SÅÀ£D1ægîa`ø¡`»Ea¹9˜¾DzÙºR¡Aa%D" ÅŒDqX0õãì3„-fÖ°Ø9r¾ëJãÝâ¹^e5½—žW²­yyÑFºÜÖÓ­Ú³M-"·3 9%РJq‹"í†Y#)³±Ia†á×ÿ +8ô4Ã*ˆ•ª¾˜ù\º¶í c³tÛ9Öös®]L»Žºë‰×qKÊ&·Ji²u«´šÁ¹]×nî)4ZóºQ2Ó´÷uÞe¯![Œ¶ånÓQhÒU,ʳ<T‰¢›FÍH#%$‚Œ¦´Íd”™eclZš‘L×Sk¥ie-2kJeFZ¨Ó쾿<&¢¬Ê ™¶­ Qµš‰ Œ&òÞ¿1“È\ÔyÂÚhLÔ:˜€‡ÀØ@“ì²PD´MÆöÑ‚—bQ”T¨*¤ƒÇ!¥7Á|ÐMÄCÎvž»£,' „aØõiúR÷– 6S0Ì×Ømú2Z£ï"h;ÝíQ! IÝø [0‚ÀZM&p2ð‚Xwç¦f6¦·è4u=F-%#)6=S½æ÷§L’G€3ãÔÄ70ϲ[”àÇaúŸ¾Ê¯To^‘$V¿#)-êD.\ ƒo†fPV’Û9¼n©å”kÙŒ&E39þ™çPGña² ±¶Ÿ”]"X+©²Lãu²R“ª¸ZÔÊdWÂr$#)‚‚f‰7áÓãüœ²tv°í#À6ðàe }z.ºtvƒ¹“˜ü¤ôàÞûp^h½æ€RZ+V»KÄnQú¹˜,æÈ^q`Zd!æ €ckb$—fw?Cd6B]«{ƒìP¹«ààL7¯¹Hg\-˜ŽUmÿmá1£ÐÄ)ó);~‡wn°qc³`R×Ox?J?®@#)¤U"¬(øz>D+ öO3VñtNê²Ê(÷ß Š5õ€Ä¿ÙÅM *#)¤#$¿<È´LPPÉj""‹hÓ4J“ÞÝTD’Mã[\Ðf¢VIŠÞn«\šm6‰Ki6b©4Ë&šd¥c1M5 Leù[¬2Õ”ÈlÔ24Ä–Š6Õ+TÑ{ÜQ´ÖÊîéjïVë]«ã·bŠ˜Œ2ÛS$µ4Ú¢¬A©£6ßЭ·Uö9 $ÙXÙ+kl’DÛ5¶¾WjZ4f©&¦¬yçxf’Zm6Q™SVV[+|;kl¶Æ#Dx·E¦ËyÕ×É)U1B¹]YªMàºËx×TdÄÖК׀–(D +îpåø8«•5æ{q¥B°CF;÷p–#$ýege ÇvGËÜuJóiÓ®ñ6û¤ÐLct'X²L!·zú·E¸h%gÇĶZÑ‘ª êIh«”ç åõðÑ&­ð¾U­o›m>{¦jZZYš[EjRš©_g—_ä~ŽµùÛål„F¬Ò¶R­ð…h‚Œ‰¾S‰ 4•!Quª5å*ºlUcnXª5mwßí¥°`tª&tÙM¥#)&*DSMM\Õ¶,•ilÔlÅ,fdµ~;JèÂQ©IjSj´Û)–²VÍ)¢•&¯­nPÉ%¨Öm‰h&)F”¢hm6ÊSHš“4YL³E±Q•²ŠXÙ2&‘¡FÉVJ©JÁQR›*J&Ù6¢“l†,‘¶Q5F¬ÚiR$É‹$¤Âi’i’ŠYª›c¢J²$mE,Lµ“²«RÊÉ&”É©Kl³j¤­ªújµÝjÒ³kM¤³i,–úJÕtÙ³Z¥-­%¶¨µ|µy³T[y›m¶²–Å|*®kjD”TE I%ÿ4ò#%Üᆽä.˜»°µíx:’¶½°†[2wë2íuÃÇ@ý#%`=S»Uá„¢fxbn*Èl""w·m NºT_yí#%Ïw²QÆ„=ÞTÝ0Q>X8y¯Ü"³ #í‰åõá€yC|vGªX÷· rY¯Ïã»êÙ×]ضh ÛYA3’ìõ]•Mù”£v”<<‚*R»LK¥òK>SËŽ¡רhÃß›ìÁÙ×t¡_¼ÔbȲ,ÒÆ6†ÈhHôž‘ÌdqÙ$²ú^@À¥7ÍíÏתüSñ#$x,¯ÐZÁ<-ÑA`}@/‘©³\#%Ôs½l#%°L>Œñä× ý9*`ˆ¥¿7B SÇ>0:³)ø!ˆ¸ÊYeiúß?ÞØ¢E™ ‹1š"„$:|1z÷ä³<õ°Ç¡¾;3˳kÃËv;oªÞ»§¸¬C'~M=xæ#%&ýÝø5WÇÇݲÖñg¨D´Œ_J‡ÕRÀ`ü(Ñ-iû¥[¨c¥ ÷í8m²@¬’3¦õRiP:Ù;$$¿¤H­Ýú:ª9¶…¹MFmiœû#)£#%h©¡#% ËÚ—Îï(FÂí" Öæ«ú>—Öù÷mñÚpb¤]À#$±¶ÆªŒßj®ëªä=œ>[îÖµw˜ÎÌTA÷Hø{`ºS«Iî“Û’’¦ Ÿ7ÑÇ.g¾ÂHƒ#$Y6<JQéà(Ón‰H8†uì#%°×xž÷áöŽ$ÖÚõéZŸ3|§ùz6möŠ#$yfK¦ÿ»µt8uyÝ‹ëp<ÕÕß#%± ³ûPÑ9‘Eqȳ•¬œç\ 3€·OîþWªëºéÑW7"þ¾y'ñÞ|;s^¬F”+Ίºhó»å¿¢o\ßa&P¨’ŒkrÈÀFa… ¨ÁV*ô4 É&j¢Àm&1íÖ‚ ,¡5#S 4?Ü£ËjZ@ÍÓ‰0ç"­²2 vÚHFsba‘#%‰«+Ì”fGM±ªÑkDª¨,Š×K¤& ÐðH°Â¸ý†ø¥[ô©5b0k ±Òôï £Âg+Ѥ£À$}ê›le#$Òб™èÈì#$q#%‘ïC~ú Ì‹D0•¡1¦ª&*Å\,vÜøÀM°HbІ}±çÏVú}kͤìÀ™3`µÙÚ¤áɧoFܲKé/Ûbñoe¨ @AVÅBúf‡WI}Ú‡ñíVÐ0†¬î–"CÞÑó7(p€#$MŒ8‹*²üÌ-@÷æîòœù,`I$c)Ó4 mýÃð˜0ƒˆ«àPù¤I#)\‡\iª¦ùåç6…zm¨þN·‹¶ NlÓx e¨k/´œXgÏcªH¹P!Vúñä ¾yðûð÷îcÂfô#áÏØ©#)g3ÕéY›h–½VIƒ·À˜2õø;3l’vÓú‰cI?\(Á7zôï>(a™®„3U Õ‚ÂR È_Ó.N z³ÉÔ S#M)L7E– É#±!b„µ#$Ø4Õ;Ô{õY#%#%Âj"…ŽAQƒ2Z=ó8#%ö§kN¬ôë­UÈfTéÖ-Â!k–FÉ#)/jPxG"¹ÖQækX#%§£13Õ®ÔìH¡fŸ<Ðä©!aDáøQT$DMšæàÜßJÐíSõ¿dUA©çÄ1í³˜¨¤ùµ  ÏÄP)ç6åç3Þ¦}dA0I¡x6UÐ[ÝB¬SIDÐã¤Åõ 2­&‚¨1Ú‘m.Ïæ¾òáM¯yIeèkA—#)ò##$®|~‚6€CÀ¥46{Î$Q4†I´XW'»Š±5‹Oßçp¼ém<Zq«ŸÖj#F¢/…2h†7ÛCVˆíÈlùò5N‡;s÷bݺ28srYŒPÈá_NÈ™Újè5îËU†¡´Þ¶#$Lˆ`#$àwøÔ“—5V+ꢕx=eê,Èõw3»¬ÞVÌóT.4÷OLœC|‡3 .¥ØÆèÖæf¥ÚÔí]v®øìpEð]á‡ÈíM-H“ÀÀÊåŒÈªâż²Æ>õGvÒEhïTÙÐm(‰rI#)N##$($'N%”‘d‚ÅuªbÆbŠîC¨Ýw}låÇŧ 1½î>k£cVBI‰­6‡¬;©Ë·cgeÈr_U×]Ü‚_SKó÷ÒxÕ¢REM*u&ÌÀÁA¤•Y¥Ã½îIB&ní:á!GuàêèµÉJ\éh9<xÏà7¹ <®®æU9Ýùß-ç±ÞëºTF"pª?UC)l3@7–ò“õF#)Õñ0±áÄÅâžOZèwg¥áÊKQâùRÚ«­ðËröˆöÛl7cÝ99öV{Mì'#h6—Dk»\xÈØKã}ÃÆVÙ‘ÉÂ,‰°îÁ,~ÏRa=9‡#$8'#%¾>|ºDª#rø‡Âó£»Ù‘Ò“¹êÚ'W¸ÈCP=x"p/ŒaŽ(Ø0  ;ðQíER]SY2s9õñFm&wT0eÄâ\´®F zž,EIiïmEÝ×I_]‘!”HNóÊøÕ{«´›µmµô»kz‹ckWžÏå<];«©’®\Å/„ËÌÖóM×–æ­²Ë(F(k‰‰˜0> ò.CoVZ®¼3!ñúvñÎ* ÅC±#%#%,Iéá9õgr¥Æšá»«"vP1AÒ¹“oÓ=^ÒÌ‚ÍÁëêòèkp¯խ:4jȸoûìÁXsko‰¾“Êü­­½TVú6iŠÄ•U\ŒÛ,Òi²ºè¹PÎ릕ØÛ~vÛ‘"´V½¥ÛÕêömkÆå©fßÊþOxµ’µ¦Ù­­/R]϶óYp®h“ Úþ|Sše>üia2뵙ĆP- ²—C€ËN&3¦ÚéŠ{àb‘Éç{…Ìžƒ\Iã6Y-U€tÁX‡`—h‰‡÷cïÁ·dfqаj,#êÞË`ï7›Î#ë’Š†j¯÷wê-)C–ú*Ž’@<ÉUGÍTª2ÕSÒŠ#)@œÂæ—#)rVl5dóTy¸}ÞTbŸ§mU5¨¤H•E8´ÈÔi+bÓ¶­º«\>m{I±FWU— a¶V™3‹$æG›‘î¨p8mç#$ˆ$9Ä3 ¬"[ËÛ}ç¤&ݤß)Tå © ü’’"s,XÚSÈ2O¿oq‰–^}?õ°ÀEÚ經`d Œ–™ =ß?¸åœ’B#$#$¤#$J?Ë@oû-Š¸›úìû-Ý,gÒs&É!È„‚. óò4÷lÖ&&’/‰£‡ñây“å¤ú²Ýk]èŽ_÷Zù¢P3Jˆã´3檆üelXrÌ1¸y§ÜࢬวðîøˆàE@ôâcé¬8‡Pë*Å]¡C×9ãâd묆ýÝ!y´Ù¿ò|¯gPïh"3ï ‚ps6)–øSTSb/9–>å~3Ð…þ3¸‡_œCÌA$N ¤ªF¢#)AUE„#)Š•T†HïFŘ‚TP‘dH¤šHT¤Î¨z_qQ°»»ÑýAWµÅ[bêT2€b:‰B”gã#$ÜÈ"bvœÓ™ôØõ=j~O·hrا#)òSóBA‰¹<éëJ4zBrN&¨ò³‰Xÿ8œ9‡DŠ‚’#)@ì„;lí-î0ÇÜ’Õ"ËaH¨«$+ì;¾¶y'Rf³LŒ&8÷vi¬Ðh%èr–X%nxs‰tP?ié=S”k¿Wq@GP̳1^Ò€#)CÜ:»øž‘ûÖ0ˆwP;1a9ªFdüãSïæ #)~©TX&õ"ŸÂÃö5¦hþEû5©†:T‹BªšíÅ4T2H’©IK#$Icº™!—íCF,Š:×ü¦30è¨N-6 £D6rÅâÄ&Ö1NáuËÖ‰0Š±c›ãƒ @Ùh)/“͸ïz.´(h…2KH´PO¨4ÆÅ\Vi1Ò#%Œ j¬±20Ì®lV5#ÓÆ6«Cm;µ¹j6cë[ϧjõmoDKn47x‹bbo†SQ#]AÛ_-­Í· øo&«ÆÏŽ×΢A’b(Æìæœ0B ÎQ‹LÈè––°[(- :”n™W5š\¸Á¶EXVÖ¢ÄÞªÖE&]#%TË-8Ua,–"‹XÓH)±sj(Ù6åÍsQX×1&5çÏzôÈöëµ¾¢éo=ís8“;H-3†­:‚­ K¨2.ÿñõ˜i–4ß%Ã#šMeGR#%éøø|¢ßjù¼âð\XònÝÚêua¤Ä´œ’S›:] ¢¦´RIÆZ±3͸´ö>€dy°áàLÌßò¸ù€ù©m²O5I‚kªnt!cê{ä;âÑ3øÍÚ¦fÍ$ZɬƼv¶ªÔÒX¡‰ÓèÄø_ù¿¡ÏÉs·¾{Êlœ‘8#Ð4#) žØþ¡ù§ÙˆX„R5pEé#4ÿ4}ä­iÜTny[&¦ÌdÔY¶í¶2WW$ÉQ-Œ4V(¹«n¥cV1m¹»[ ‘ 1#) 0Fhš «#$bv:`nj ”T£Œ ý\3ôÏÂÉ¿ï@tngËðôñõ÷ciçMZ,`nqùý&kŠž:"HU¢©GöÑAhÁZb5LƒKº‹,€†K$"Q" k®¾¾ºl4JŠ:qêökMÛÅ#$ œ”ÜÄþ1ƒxª¨$ º«šMëW —ÔóM¬–ó®¦l³mÍsmâ×àV¼—®Ôlm“`Ö°Ù#%¶:V6+ªîØ«Ö #)½‰!zb ¤T¤‚¶j‚B4ÄÂ’kRmT™¦¯ž–±$4T(Aº$—(<ÉŠq®ó2±û9uC©¢àE­¬MÁgr£—$ŠHØWå5E˜2Càê#$€aP3 ”™ƒbL²,–0â¬-#$/}EA¦½RÉÁf#$!´#$/7ÊS RÀÀÄ/HpÑìtÞ8£”‰Ö6) XObûd‚†¡’%ÇŸq‘ãßNÂðM@DÂQï!D*ô‰UR&AWC;ìÙ% ƒ¥#)'£° Fî\I¬ã·…Ë(™†üxå\ÓϦ#)T?†ÂÊ#$(¿€|O§”MîW1 ª8tîØ`!ã$úÃȯXÈ[MIT ˆ)m)SÚ-C-5ó5Ú4Ö³JÊ{+¨ÚÄÍDQ$¨…üðtñç<ü»}]¢ŽPì·fûZ¥Š `mnŒŸOŒš§•³Õ”8èQùÇý~v ö£9·æÍ¥¨4¨aéíŒWšêàÖÛÓÎwgë•yL¼óÆ‹­ò‰­êÈo¾wÓ"tÚ¯y#`”PP]•Œ6ÀÞåA im•"p£è` rÁ“ˆQ&·‰*†ÀYˆâ=ë¿Ø žOgX ¨’D’f'DTGôFæ.'.íŒÛë¾Påó:‹ÐNfa!H@ÏzO ‚A;Q+BCl1š!7aJ(ÈB˜“üßo q“„“gGA7ï†õ3Ãu%\›9¦#õØàQ€à› ²'‡­JŽ–´ª*©ZQ¥Òé©NÖlÃBFk‚91o³mx6Â#%#)1ûÙ™&Å0Ù#%9$¹Š„›b JD3¾JR™Cî#$õiÇù²v?oq¤ôf†fâ»eŠ>Ž(q±é–9lQ³ýРøü¼mšãj'ü?&›|.ö%áršƒEζö™œµË3ÚQ•ŒªO¢²uuó§¤=Oµ4Íz+†¦*f“‚F¡Z¶0B(A‹Lkl ÃT””›4–ÙkMRlkFF3M~‰]&‰*#%K? m®j¦eSf6F3I´’¬Ú˜–-e[+6²”Õ“kÄZÅ¥lÚ™K5©¢J¥b­±´‘¤’HÅ"ÌÏÈóQù©„Oö?;IÇv²[ Ò3QÁS¦!Ãö¥€5$Kk©ÊÕFÔmQk©m«•»7ƒo0¨Áoêµ-z­uo¿P:‡™ÛÓ¿!#%ê ²b5©Q$E¨F2]KóêoŠÛõVoãÒ«íYü¥è$”WѶ‚.%PÆURت;¢T!cÉ sÝcŹ>% îÞò°0\#):÷m¼HV|Õ#$îÀSÍßýŽ}xÅd#$¢QÕî ôÜ'¥9gö±RýD„ zb–ˆ"T‰öÀ¹KÚ–é#$Šñ¡},ñ ÙÊñ-Œ£Ðð=ÙcýYí7mÖåì#$”W#)ÉÄFy³ÊêVšÛ< ,Ö2¶ÓKÉ“'°ý²¸ ƒ—ä[ 2à–Bn>8Ûðõ*žr'`ò0d‹â3¨h…pvª›Q3Oy°»½x==@dï î IY °‹ aP&­É<yIc_pqCƒˆJGÝø®˜rÏñ½ØO8ŠÖ0† «#% $ŽâPþ <ÃGNB¦ 0¤ Þñ?G¸ì,ù¢l,{Pûÿãûã–•ŸN³k#%4GUÔ/ѯ¶)údû{Aé¸Ëj6JÝÄ㌢u1%z¶Œ‚$ˆ`é‹cþžGF+D/âׇñ»Cñ^m<è„!âµÈÚe]ͶÉ3’_oÜh¡¶ êó¾-ApÐHã0´EM4ÛÈB û0‰¤ –|<#%1×jÔ>Nòý.’(d($EQ '‚VW-qŒ Ÿ³—­ò¹½ 9>oôÌhÔ#$~ŽáHå)R¥,¦üÔZúu¾|óÎçi‘qº#)¡,¢‘‹íöÐcÒ—ñ³ DP8#†¡¼ÜÕ†c€ÛexÀÆV#$0`"BaKSrÂbB&²Z°ø\73±íèÞo˜lip[}[h —6ÉiCj11 C§#)gï(ÒDL6јÂD‰jP1Ê€#%à žó!vBèïøçËú¿&×n{KÕ%‚å3‘«…ïaÖóxÐÚäÊ„&Ö#%G£Ã±sxFÊ®ÉØuhA × 6mÔÍ/–o&ˆQOñŒïÓ¤% î›(XÂ(xÐ4E,„BD¦„ƒ)8´p(EêDñ ¢z<¼)y\UG!Ôîñ2P1êæ‡Âr󇧶¨X²,ÐЪ`T¶oša-]Ôž´üS.ÐÊ ç²ÊhmÐ,‘¨%`÷tÑè1Ü?PÌÞà®øöÃ,È€ö’CÌ!í&C6ä#)ˆD@YhR# ÆSQA†ØFþ™ø>2_}m÷ÛQA_™ºU+ÍÛ[¨­úÞW…ñ¾heãÇI¼¹’HJ»¸¬éHˆÁÅTU-$äé¨_* Š¸‘Ãè*…"­7k *#%¦â7¥ÚUŒß2Í0dÍÖÕµ­¤âqrcš¦\RA„%G¢#tÃìż8اfÓ½]€ÊƃXcÙâw4ÎÆZgwöÝÄ5»¹U÷£è¤_vUcŽ††Ú 14®\¨#‘ l6õ¥„æo!©€Ÿ$‚Dœ”/ïHp¿>ãŠÝ!b=÷;’Ÿ†þÞrk#%Â_SýsÕžCl ÁãÀ '½²æàÈ[FR(ÚbÛ&®Jª0 uV- £ºÜLî®Ê¨DÄ•Êæxè\hDM¸åFx|3!ÍM¢pÑWDó×(£W—“9©×..NÏ8#%Ÿi é)bSõçnê0†ßO#)ÔêrÊtq/–÷†6äOˆ…§WóU¦®äLÙÌÓL|3’øàÅË ÏR¨œíÅòÖ³¨%®¿Ùý©ë·íë–r•:è ¶lo.7ª¡X$QnÁ¢† RZK-…²å£ Aæa€6U¸¥Ž”È)ì"¶"¦ŠÍþ‰Õõ"+ÈÞmÝCàAÝþM v`­@&>¬=šmÉàt`Øé`¡‰¿«Ò\8Á„N J:éܨC8§^Ì#)Ì($«U‰`ͽ­‚¨ï(ÙCGåË£—Ÿ@2Û´êÏ"l í·š!Ðû<ÎO2'£»XÞCO3Z®Ý{Ûz`K"[KÎÜDal… Ø¥q"!·b#$Lb@ hÄÈèÁ¸Ò R"*©T!`¡#) $>?73™ÐQAl Gûi½•ªAßÄA°&Ô›£jeUT@HO¬þ«lþßzÀ­ŒCÅhŸa+Zi,j±kP‰¡ös=å¯áÔ)·w¶õÔ¬cº.™p¸±ªÛ@‡ÚŒ¦y—Š2m¯.w6M}cÖ·¯€œÝ­d›q ŒN§+#%b#dd1ÖŽÐ\Ô-4ÄÑË1éBkTÅY¨¬!²«›dÓÈK¼¦y¶FÖ (¤$™8 pÖ!—jÐ#Ca†·ÃÐn,ªˆW!wD 0ðb¶[0 eö¯¢#$ÿ!ÁÂø™„„Œ#©T2ÛR4X7©Û¿Ê±• Yü¤péóU6u,<ÞaÁ‘Ý«éBöàM“þ÷cÖÈiŽ'D÷/Tôõ B0 $ˆHã#)b‘e¤­™hÙ-%[¥5_¡_¥·ëµ¤Êë¶ÙÝÌ[’Ô#)Q „CéëNÀÒƒäÜ1ù˜s…–B‹›¹¶©ãñ[€E‡—e¬Õ¨{fáÔqá¸ë2öc#$W"Ÿצ{Ê:š?†'R&A.ìèskÒœ Þê<³ˆUåŸôZï­o6Ú58U~÷è²- ²ó|'ÂÃRy-o£5¸Úa$Ù6UoØò™PÐþÛ×Òc†þó{¾2}H`¯”M@æ ´¥ê¢6`C°ðÌ:æƒ./‰dÏFg¤É„‰!2dÛcéÓs±‹g¢³|Sòf²f̓Xf­0ìnd«#%‚VÜÓ~·#$Å´S-3JjÑäJøKºÆ­žœùHÉ ø¼±ÜÛ‹n¿œÎÔp9ëà–«°ÉÒ.ÞGj¦4&zýrøŸÝ뇣ma±/ŸìŽaSYëÌíðõâyÄ1àŠ³ŒáqÙ´ôöýW›'c#)‡™¨Rß\ °4bbU™B˜æ+ÌJn.tþTØÌúQÉðLikâ†'XÏkW®HâuYaÔSZ·°òü­#%¥÷ÁYM]¹úŒa;ê¢IîI3“§ëÆüç_^ÎOr—»RýbPëð5d†jØŽ¬§›”BáEA4¶tCCsþÍsíØ4d³»\ÀçÑ}0OF#Ê[ã‹és—µ‰ ³©ÚÑF±‰Ø#%5"+URT‹ˆ¿qRP!Ø/žøîå´#$A~GtºOúÿ¤¿,+(ˆ ධº%ÄŒ›º²Ø\º¶®éGƒ]Yçnçnçwµ+mL­oU«¦ÛWîM¬•ë_©&Ä!41¥BûMë‘s¸ééätãàzˆó8¹(’L>oßþ| ;p€äš´¶t’¤4€#ìÚžü’ ñèÙË–MÓ7Íys í®=l ½Äìsn[ˆ9à"mQ$ sÂý¬+4æhë]["tÉ3‡Bƒ(u#)cE-âj<„–«b/Ôlweõ0` í¿fÄ!lAÔý¢uü¸š#,vú~BDV_Ïa‡`568÷Câö-QU ÉŠ”œŠ·kòÞ5uT6îµuËrì[«¬µš[M-hµ))fm­™j®«cEr™x¹&•Ö­öKB$# ŒQFDE‘A9ØÎl#)x ø?WÜÐÓ_DS®©–Ù‘ÃRØ ¿™ dÛ»à–NÐùTlmp0q¾¾ûVc…„Çð  Ìý< Ànj‚˜ârÚ¡–oÍ 5P¦o°øDFŸhˆ24Ž2$t3i0Æ°°à=9ý-YØÄŠY )AŒiò㾃§óî}vÁQÃc÷“nÒŒM¹®7ì#%Áu,ëÁî7)‹+X6h^¦oöWY·QïD §ë¯1°C/J1n‘âtzv-¼ÚÊøü,3<"#$iD—7#%cH:V•µ‹t¼õ+{ã âV#1Er•¾Õ#)OÓt“\˜Æõk¨ŒÀÇêMb“d`ÛúËæÂ!±…™¿lOù?Ëþú_î7ëP§ó!&R¤â¨Ö9³æ¹”‹âÅ‚F#)JÒDøvÒZ¤(M¢9ã¥][¹”4”…H­±0¼d#)CôšËÞÐètÉ£ôµ.Ǫj™HW’6Þƒ`#%H(3€Ìv-8x$Å;`RÁñ“¡Ã–×$PÂÜûÛ¡‹G‘"`÷½#%‡Nˆ¡’Ëô¾IÇ‹äGMé«c–äP5]Ô@}ÿ4ÿˆYäýÛ) $y”pùUÚþÇ®8èg*«ß&ᤎ§f¸#%äxñëW»ƒù_¢ÈÖñp™³ ÍÕ˜o“…ñ =Lo¦#$ö ¡UïÌ«<ž6i´ؽ¶#%Çðb0ˆÃ¼;àÎåéÒ(íÒi›€¡æ]&#×ÉI…ò#)>ê¬êIœëPù²– zr\Ckùƒënwç²Q—d§÷Ö #)n¬Æ:×i¿LPt5;ÂCPÂ)´ÏU†ŒÛ©™¦©²[Êcî­ŠÑç½JèXÊ8ýO»CbXFä™a¹÷¬#̽BΚ>}#°åéXj3û#!CrjxìíÔÖ08Ø+KV{ÜLèO53ÍŸ ô™á€†nEåòݾz¿£1HŸ€‚1 à„•3; döt! #$˧[¦qŠ¤’ÔT‰Æ,–X¶¨µmFÛli-E©–Ô›XÚÕã–ª6×-Vû)Œ.ÇSC»èÓ—EÊåQ¤¹–¤±P#)„?6rªöGq±$ƒÍÓ´àv6ßvþyab& ™<Ì|L‡_ÌÔ f*‰#%Už}¸}'6˜(eõQ·fØMj~‹ðóã>Šcâ×M] ÈoåµM¶H0I#%±¦7C·ZAŽŽa8w'åæSÆ@Ùâz2¿Ùûý` ?D@ª¦‡_>ýÎ#$ÍÔ(”“¡AÌÀ‡xRW€ßO,ÓÀº?vƒ»_¨LÆ‘î8ØD ÜÀæûÜæ'²ăõ3Ž]ûi¾¢1Ô=4=•¸¨ wÄ0ÌV1yɳ”dH{³wÅ‘KB}éªm»J-ÿ÷¶Ú`”&ùÔ‘X|‡Ù z‚r¹6gá#$û ‚“Õ¹#p>Û_&ãßÝW¯q»‘zÊ)#%)¨9D¼@è€<-ÓT€kã1°¾Ž· Ò¢ GGFÈDY?Ò!h(îNçA8Öý]-{¥ë.„6¢ [n#9†ðÄŒCdPÁ4RÕ#)€ç¼=þ2Üác¾W_n§ìµBV‹—HÝŠÐPÊ®îÛ®.ìÞëê ¦2ZßE¬ù3èŸN³ ã-O%j½þCèÙ£Õé6ù$|E¯¬í—¡öÓáù2d|•´±<gíýø\6x‘KßdÚÙ§ZpÈïÜÎ^1ç\K€ æ~»!±qÀ±aMU<ˆô©2˯môŸñÛNºíÔó}~Ñ>¿€^û¸#% ÀótM¼: (¯Qí ®Ï^ÂòßÆm¡ò×#)Uy¥¶Â‘U„Êæ¶Õb#H´0~C€#8e+ÒM&]LŽ’—DJ¨‘ÅP Š#%j¶¬ŠBŠIÁA¦’$&›R™›FÂÆ£uÝEz uKùžñà"Âë lÛ,بZ18hÀdh–Læ†Ê`”Ð1SKC›»#Nn$“0U5$2H¢cZh%`~jA¤067ï͈Y=?l¶%]à)‚I´j¶Mt«›ì•ÑfÉ«IW:IyÝ»¶TšXÙUÂìKë&Éœ°B1`âT(HªYE&j…™Î!l‘ˆ1Q”ÒË=I^6ò¥¦Ê™LP#%F¦ÖR±,3LZfÙ$™´Ø¦³2L5²–—½Ûۭɧw9·%E7]\«”í×|]x×›Îð½»\¤Tª‹zö÷³a“LÔ<¿Œ^qóÛä¼ÉqT UÌÞ˜(fÓK0 ˆÅZx9³YV€A nºG‰éêÌcuÛ¤Ò&Óµ6;•VŽ#%¾ÊŠñ„‹#Jíq[DŸ.<˜g‹o`ØP7ÜŒ4×b¦M¡»âe,ÚAí³°© ²EX¶¯mt‹·ÓºVjK_Et™ 4æÌË%ªÅ¶ó‹¤l”ÐŒJEÊÐP2 ÁŠÖnd‰F;\4d2RP3f´ŒB‘X¬4Ô*Q˜b’#Q±4 oqm,cJÙi-+BA)#)ês6ÁŒlI» ˜ÐÆf;jc ß».q Â5àb·!YY…¶ dâÒ«¡×#Ya ‰¥Z &LW=Ù¶²C$_S#Ó>ûL“aB4SØà£Ö‚&ì¡S<¹Ë†ßjjá4:éTWGˆ'ÊÚ™±˜ÃÓÒcz@­‹ºáT¬)™5;›f[:¢á¤´ñ1 -bÓ6ÞÞªƒ¢òÄ*ÀÀx3éÈ‘ò5Î#%F.ÂýÆê#%šnX¯h‘Ÿsù0|äøžKeÎÓb6LÌ4Ć…·§1$Ê æªWz%I]Ä#%¥¶äDdbŒå‹$1è!f•O#1E“#l3&m’XªZi½d[Öõ ¡G·— ´&µ¥Y¶iSYpŠÇ-Š”/’ÔѾÁÃÁÆѾ7möötÖpÀdz m0¡ºe×zU¸JEï#%3¡¥¦!ê$åJÜ,eeU»côt!;ãÞ!`…Á#)"¤ÀÂÒˆ‚ Hij !° Ð&•" Àa€LAŠ#%Œ ÑHQ,F#%’Š¥Š.ä˜%ÈI.%þ ˆÙ¿‡OQç¨êl#$kÓóã=—j]›§êx3³qõ÷5‚Õ‡û±bÂe4~©.0¦*àû>Lh™5ë[ƒÖ¾·J¨MŸánšÒ[~Ÿ×¹âí…μZóÎÍ"ooOLzÅsÝ4<5¢àݶèÓo=ûº™)doowIÙœ„+=uG«8‹¬ºÖjcfgME,«8ÕÅ™)ÃĽþ‰¥dõë]ëöÎïc𠌼@„9Qy·'Q³yÑ]sÇ™· 0ΟDð›ìldêïß3\p6´°+ C“)ßpxÜ2©´°›"Hº®mÊ·{óO†í¹ûûŒA¿=EÑA¢vÚÁ$yy«@Í4bK~²‹è}xb|¡ÇYR:{ŸŸVvuè›÷"åÃÀ{³P’X§„ç#$ïŒ<ৢf›²¢©–€[l¹$‚Bļ.ˆ«µ² j€6… 9Ø&n}”Rô#)‘±³˜ï±m_u8eh&—®8‡ú’@yÂ"yþ™‡—8GÎ[Å$$,m„ª[}uü;Q¶Ö|Lºo,ÒÜÍ>xÈ š6D¾•VÈš6%ËÁ¾Z£’HE#i#%Õ]ZñÒÆñ­Ù«p¶Ü¶ÉUÞ:6*Ư:åÓWVÜ«»s!—/QN¦’Ťh¤ceM¹Â§vÚ5IYTÞ¶Ûů6´›¦µÛuçž1hÆÖÕ‰6€À;#†DV-™WÆÅF7^™c"“>NgÇ ¬‹i$V#%#$™D"…E… ÓX%¬ O<‘Bê\#)B.øÙa˜”¬—Isr´×Æד4Konµ^Ô …`CÞòß&Y¬VR5$D2íQ-oº™ªIüÇUÙElVA2”±¨Ö4TÈÔZ*-¢±Ze`±ˆ¦Tl›e$ÌeS`©™,cUM^íÐHq©¤#%Ç·§Cቊ|zþ#%BHÍÝ÷µV½øƒIm¡4d¨eS¼OŽÇjÜ™#ßÌàáýÛ”0¨ê Ä¡ÃeLi´qzûN0PDŒ€š:ÒS-Eù—<”Ùbªý[òµ­Â­xÚ麨¦yºèÕ;»tµÝ¤¥¶¹m£&±[º»JV´Ö²½íÙ¬©Ab€ ÉRŠŸÜ§`qÅOÐ1:#$~{)_²#%!¬C˜š°&1TP#Å!¡UÛ€#i$€H($s£{jRÜutp h”ƒ…Ò»°§0Cl¡‘pé꧓Eã!ªÚ8yÃÔ\J~Òo=Ý•ö<@öà£u0}2/ÞùQXA Ä» ªÑ„È‹éšnBæ;Ä|7pDÿ®¸™·7²™˜Ìn~[)$Æ2»™&š„Á4‘3ifÔÓ¤‚M0Ì–çjmöv™MÊ[]ãí+™ú÷8òï9„›YxLh&!Ð&;dé¶*ßÑ=˜ãTî°…#%l‡2}¥t—#%˜U{FK%j¼¿W®¸9ÂérAs߃f›‡É„Ê´²ŽxÎMË°²Ø®‰h¨8¢iÜhp³9¢¡†˜—w³ÜðtX*þòvЬDBt`,:ÎÌvîVCêì7^W±‘Sj›'-Ÿ³OËƇ÷V=0TLF>=f’åLáZUI ½dï|È|Âê Ì2Tãø@FAQP„W@‡DB "°Pÿ@Ïë4ÅI ¢–:º­äžº‹dÚÖ5hÛrÖ×€äqóŠ ûBXýáÔ9ÇÃÃ’2ý0$#$b@ ÇeÌ}Å!ñgGîLÞ` P…JÉm5×gÇ-´¦ÛtÛ^Äñ(#r4Dh‰xa"àÚ´4}ïf¶Ðˆ6IK#$J`•o¼M¶Öd˜ÅU^,ÛÕî*¼î®Äø]ãk©˘µŠ¨¼¥ï#)±²¬bŒ¬HáY¼Â±æ“µ²3(€¦`Ûe£lÕ©J˜ãih"«#%aF3ÆÐ40¡Pˆ‹*-lX#%/!•°“0ŠŸº%f!L"\˜€¼h>AüwŒ[i±8ÓH‚#)"0õ’Êy?—_)P¼æð”…âÏWD?â}’O«ÖÐa`ªsë> Þ!*ÆYõ,]‘³nÝM³ÄÁ7cÌ5%¨Û·?fü·fÐuôeU‘; 1’BB#$ݨ Š¦(@Còõ½ùcóûÉs C變†ßø‡|4ÃûàÀú!’`ücê—7côÿ@g”Ïð04ÚŠ¤¡X÷;À,Cvúï¹÷ËãN`ÇÝ#J&}¿–ËWYÏ›‡ñ:hò7züŒë}|vvØÿCV¢µUÍ 'Û}ìèúQ40¹Û¾q½Ñ:Ý$>“L‹pP#%í€Ä«#%4ØϘâ›Û#$HgÞ„ÐqÅë²6Öó;Ï\m6¢¬Ö¨©ji-8  ¶.‘JPô)`¶ 2H¢´0Z¥!²âØ ñû•?hA]"®EykÊvNøuû:‚KKä’_Ïš]¾'á¬Ù›³–C¡Ó:é|UàZàsM¯mUªËšÍƒz|Ý#$×àê?¹ÒDª©EAJ‚%R0h ÒÒ†aD,ÿ]Îê#)¨•#$1{S ¸ÿ‚Ï…Çx!²7*B-P%²HÀZˆB„_˜\°'Cò㊠$Æ‘ª—‹»Îë#.Up¼]G—w‹ÈlJrÜËÍÆÓe“I5 ¥5G·jm’±Rl`ñº.mͨÎÓy¼»q×]³è\®îÝ"¹x·%QÊio'“]§5™c@íæÛymDVÑY*±¶‹)ciå¹K3IRVy×t—NmÝ™ÓrE*w]ŽUÖ\ë66Ûb×j[sÔ¿ÂêÖßvò—U_Rz`#%† °/^ßFð|öC°·a 6r£öy¨€;”þ®ä-F C¾Š ”'k,ª/¬ÄDN)ӊꜧ´; ØCÐR#%ÄøÈ #)ñÉôǯÂÔW¢û#%žÛ_ fÂöyòîŸe—ÝmÉøöͧQìÕ涷ܖÚ5™€¶¨Êfhg"Ân|ZVYA`bÿ`ŸÑF0PÎtûxØL B$ˆ°ˆbªÐ¥¡–|µ|Í~ÍûMïÙv¯ÙªÒ×Õ˶4–›Të®î¥•‹›º×³[¤¯Ö÷y‰š‡ð «¹ b8hG§àA 9¶Fn”ó¶ßI1ïtÉ’J#%$ÇbQILL-˜áƒ(‹ñzÖÛɶºínÚlûySâ]umÚ·d¤l0Ð\4:g³~õÌL’„ø*%gLŸÝÀõãbPÃÅ`”`{Ûû&‡¦°#%¨ó#%ܪ*ïˆ,€DR 6mYMªU´«,´ß~‹À vìù Üé €¦¹ˆè«„ jFËI3TkmCmQWG‰àÀ7¡¨GqñÓ$ Œ0•kûòÚŒ­#%jš—·µñ÷@€ž9ÍmL÷W¬]ˆz"$§(©­ÊÍ_êøD‡pzF¡&ÐÐÚz}¼ïª;“qÓèî÷mÝùî‰ñ´‘ˆrB!§àKÞþÙùmÊðr^(ÁXq„±ž„#%0pl‰8z-‚¿—š.µ#%äE`*͘Ȥé{â÷ båpþ€@cÈõôE·SØ(aþÛM>]£@R’`€2H–:É-CJ‰Ç„"@äTW‡n›Xø{íz¼«Igö¡ZDh Æ0#hM£{€¨ìZ„%D!#$ „Xó›e46<Çåw•åoµ‹Å«š/r¤¥&HÀ!hKAÀT‘¿'VÅUwˆ"¦gF £à­'¸ÕâÇvvUX7ÞÖˆ²L ©"ã#R\¶7‚6ªª3ŸÐK&YdɜЬ…Ô‹¶)JU†±QŠ©D#$¥I YT°©TT nòâ™DM#%˜¦X‚r#$5)7nÜ›á4qû¬#øŽûµ#$¤ó͉ãXôC{ñù‹Âð£IdˆUP Œ¯ÍPP¬& ”j$!¸ À]/c?*v0ÜöC&½´œI"¡Ä!ÚNä'4”RHÕDU"J!PªŸº)ÐDü" œ¨+ê‹2W^ÚvÊ×-Wš#%‘¨T„VX‘Š-!3#$gŒŸ¡ù¢Î¬>g„Á!—æSþDM¯ù}Òöl¹–[Zm,M.ú¥_c[_NßWœ¿Lóºõ¯uKº Ú¦¸ºÈ6ÛrK&8(BIjº5GLÆ슕ÒÙÅÿCPÛ4´(«rx;¿è•VN#%œ5#)²òªÛmW»LW÷N…èxPé¦x#Ô£â!¬"xZ·†Ó3´<„sÀ¨'éÌO¦;¸‡Œ¨¶~j Î ›à¢n‘ü`¬Š#$ ꡦ +H¢í«P@æ¨õ„#)'TÉgç®›[÷À-ö(u]¼S[Û¼‡OëáûAÔðÐüF ¤,2?ŸÖ¿q­dû·—ç(™(!£ðS@·é‰ ßóô•ê+íõÕëƒ?"· PhžúØßòÁfÍPQ—áÆ ÷¢‰#)2&Óóc<Í$äÙ%á¥Ñ}GÛ ÛAä¯ó¨^Nã[{ð…—£ÂùTÊK*êÎc8sæU¹ÍÑŒ´Òk¥ç‹#%‚dgB©3(zk±•”’ú™u(2‚¸©R +†AdÃ6ŒH–Ÿ/“½;Á]ÆýÍŠ%ùAû>Á·yÃÔ@ú‚j™fûž ÓÛèkÎþ±§•÷ÉPÑŸ[ú^ñ^#Íg¬_–=×Å'6s UF¤“ÃðìŽUTæÇ2KÙóNBGí}Uþ뱆aóf8” ß>s%µœW½–üûKCz4È Á"Š ­Ì]³—ëÕË—‰$¹Õøê”$±>ÌÅ£#)µ›ÄciiŒÄÑU5£ìg‚O#%\†ŸÝ0¹~/dëüsŽÐ4J:q‡YÛXòˆË`L§«wF}¤ësKáüo"‹`±o4¾gb·¦ xq=ë@}®ÍH%cæÉÛfõß|ëA.H4mLû¹Þ<»BêCôÕRn°Ê¾güUWÇÁ™JZAZ\¯[ÞšâOŠÞ­÷2 ƒIPöÖþѤA°^~Ūuæ¡éå¼ÿ}”ÖIy#¼Z;k“‚ÊáÄŒ ¤ºØ±ìlXˆKz`„P£h˜÷ôÐ#%(*HU°=s²«.Oa4Ýî/i0UhP·`‹A°Ìª ä÷õtôíÏ %O‰g¢]P¹g ·³Ö8 î8‡aDéCdC§:JÆ%z‰$F+å¼ó7~Ô˜CQ°;güÞš–.Š!hq,ÀhOiçO¨ˆÀ¨H¨”˜A´ÄTÍvœÊ:wuìA@Ú2=oYo.¢!BPÿÈ£åT¬ü‹ ›kR ík„àjHRI5_Íò»#%@Ýû²×6ý·ŒzÖ®[^M’ÛF‚9ˆƒKÛ$ŒâÙš»z5JX×ÁÉýE½¹B‰ jjšhêB"ü±åªµ$ìñÉî‹ÅS½ËÅ…=¥<5éÕ–V¼XÎPÚ<L€É;ÕKÙƾ%‹ž½/ŽÇ"e=¡eåe¯bjIžaˆU±´Q¼T¢ÈÇ© àΚ“Â)ùëõæu†òÈù»–™ëš¬—ƒ„gÄ›¦–î‡Ð>ø'•NçÊOw*4Íh¹j2T'+óÛ¸tN#)¨53lw®±($^ ̲™w÷ìmƒ]ðÓ MO&ƒÆ+¤!è|vU]ÏN~Þ¸Þ ×¯,AÈ| ¢iÂí ¥›\P„Ä»(#$O¶€˜ Î'gŸøý¿“0¬']O®PÚ¾ v H$‚–Š²HŠu©Ø÷£ÐöÃàü¢°nö‘QBA DŠB‡nÒõp]€>û¤z«æ>ÚódÄgQº’ÁCoW Ç 5=§Ñ‡Ö{S²\ùyÍÌ4 p ‰‰¸Q#Øsâ.;~;C§¬úÌÂǺo0íÔáâá_•B¼¾v’R¦9Ý«jÛçÐxim¦×ädÒ"¼Š:È9CÝAðIÝ"xBEËOÕ^î®=Œ&]œ”@õtQæÚrQpQÊÈ(ã…ís1QßxÐpÁcä žö%#$¤"$:”;~(#)H"„"vÄX¤b9ñ¨g[¼-±€žÍÎ:‰5B£«ýN#%!;RЬLcJB@s…Æ-kìãûß×ñfVXâ÷CùJcEíR6ö²µfv©#$Ää>Ý»<EJªäH#$Ðxƒ¾4Þ{ip'›¦Ü0y~“q†¦ËªÑÂ#%·ïmþkóSA¬ÌûÝ3:1CG3æCq™¢#%}QAÒ\ç#"éLfeæ*Éh÷E¤¸_g8[é]•¾dfD­#$zƒ!væoÈøËpij{Qˆ©ÅÌ0@ßÏž0zá½öÒQÑF­¨˜Òo. kÖÈ;±fTLI9–‰5DKœ°_«Xàˆ0‰2B|mþ?£mmCAË4{s 2? GÝùòð¿³Ê¢¨ª'×(³jlÂU9©#™ûrë˜îO~ýúoXʪqÁ‚Ã~ý`²=3¶[^èBöG/#)ÅÄùè¾wc´°ªªÖà ¾Ùr/Ý#%ê’;°¦/”` 0Öˆº{0:Q BC˜Y@q líO×D#~½k!ԶX¤ó¥&™Rgn9Æ°H¢I§NNêåk¹û÷j¤£XÆÚËe4¶lر-jQª›?&í–CsÊ”/¹…Åbaۗèù KU >¤ƒ*”ŠAd¿ðã1~ÿiw…&É™²DTÀi¢‚RÑ(–’$Å‚#%)°É±4) 6l›(HÌ-o¿}z­$#)%ä‚S”Ä¢r”·8ÁùVyppšR’u1 …NÆa³”ØpˆFÓˆÎ5‹›Ç< ²aÛKå,Ú§¾¬ë·Ø|å÷MåDf¹ÓJµ/¨N» CaÄL„ñ^ªˆ¦UY¨¥ÍK%ÚÖGî÷eï£i¦A?VîÒ€HºëÝÎó/}M³á“bãƒ^°ÂíØw³yíPèÈÀñÜ9«PÑÓZ+/JÄ#%ø˜'BÒNŽEZ¸Ð~sòêÒó*WÈN!'Ýüa!ø¢±1rTlÁ!­¨ñªÚþi&ÁõÚ¹Õ\pJƒRi¹#$Iüˆˆ0µ–ÁTÇ)O3›rêåom/%…¼&¦Á2Ìë{HFj „dÀ#Á¨Ð(1‘¨@£»)(Ûi%#%•ƒÈ*%+lË ›hÆ@Ð#$±€Ø,aX‘<4A#$ÌPÁ¤B¢TƒaSi,jþ¹+µF¯:íi•r®\È219%œ5ôæ€|›]Ù•tRè5J å¥˜™—HG #ƒžÌY˜6XÞE|š‰FŒä­c*ÿF½Þó].C<dâÆ. fšÀé<e@Ê*9“sGIö±a½Jw©£4¬*ÄqCE#q¸tSŠhid²a ÚÍMM …Ýh¨B‹!hIˆ#fG!fjƒ)EÕ,Eë•%#IƒpŠ°^ÆÞI £§®ÕlFah ƒL!ÙB´.¢œÑT†M¸äMD,e‘¨›PÓ‰§Œx 5ªØØÖ&á$Pi«Ç¡¹0„eQ2¹UiÒÇr&ñ`Ç#kDÛW Ö#)¹TNÀ #)ÉhÆ:Ú¬l¥[ o0™† 5!§Fâ‰AŠƒ¤;Yp+ÙÙ¹nñïc™ww´M]]fUtiÜh1Ðf#%M2ïmkK5£>cÆ1š7µvBܨæ®· ÝbË-­QÆV69YZ±¨Ô¼\}µ˜Ã’ ¿?ƒ\qÈÐcQƒí#*±.FA cklÛ È'{B°ddCÔ#%膚Ö#%‘׊Å#Ú‹SÊàÃRÍÓÙßZ³¸£…!ÆÜÁið£p¶AŠâä£#¸TqV0@;‡HÈÌå81`KV“Q¡‘ T[¡sD 2-™A¨…š‘¢˜s‰£«„35I@0Mqåø„ çd×BÍLFZx… ªÐ"Àl¡IH¤5’´‡"£Uëˆ CKÃC|ü|y¢Úzªæ¹S5eÝ¥ëRÙ#)ˆ#%T”% …(è–$œª&±§÷LA½Ýò1¼3"¯”€Î^†Ûxà莆 ±TÐA0T‚"m#%,-srÍG‰(›Ñìaœd›#%=®Ñ&ŒÕ"ìDÜņn,f½´Ìí7LØ0€Ñ¡#%’£X´4Ò¦®6żŒ±¸Öé; G¹=d{`jòTJùžÃ#%¬å.ù¾ÇXÞâXP®®b"UM}ú4ŽÝ#$cfѨŠ© ç(†ÑéƒT¶¨íñ]ŽÚäÖ1@‹uË4¨Ž%EÛäì€1æé­Ä`Ñ°EPH€‰Lèš" ‘¤´Š(ƒä€Ú@¡Ch*±%EQ‘R`ÀF#ˆ—´–ñIÄÁi£ëM@*Iûz{’5JS”6Ò¡Lþ4Åb¼×J¢M»Þ®¿Ùºoݧvܹß]öWêZJ#%µÛ-EŠF,HDJ€Õ+ª}ÃëíÊ€q^‚Ü ž—uÍœÀ**5AÓP Ýœ¸$Kx ºŸOïËÞôTAöaJa¥ÊŠ5ù¤ªÈ¸&áÝ$D!#$I‘ˆÅJ3#$Á.[\ñpù«5#)@ì=UîBsuÓëgi(&B‚)÷NJ’ŽUŽV¨Á PbüD^õ»Y!ô´®HÚN8±lmºººU·ÅqÒ‡wFÁ„í•Eªq¨bP¡›™ƒ`‚{מJ#W×Ý»}ln6§5¯ß+<H^´a¹®ì· Œ6oÊ#)h`¶gÚdÇUúþ-A¡[d=&m¨1‰vw’ÆÝoÆ¡âuÒ޳ݻ‹'t„YÙI€Û㺹›AIY£#Aù„‘ ý-vbŦ/’µ¹NÜð¾q€àÞÛur0O$Pš‡R—ΊŸ®èÌ‘&/7á—“„¹k”DÊ"tÀ»‹™%eí;w‰¢a9}ý;^ÌǶֲxÝ Ü…¯z(#%m6ÍôלåSáÕ¯X¬ø%Ð2׫ò#ôXv¢#%ô~sèub«frIÝÞ/}¬Ê6pŸÚÅ“ù }uó[~ “BGŠhW¢{Žòa#%&xQà`¡Äˆ‰!k»æN‘1rÍö7´ïp;-P¹ÆQ8ÂuµìÑ`)Òib¦½¥T*›˜;kMM ·Xè(#$ý?1`{ð•NÌ‹k#!:…²!Ús;Íbb"ÊQ`‘@U>æCèÉ0öÒ•J3ÛU3·©.\2'è~­/•3Jš·-*  ‰ÄC\ËJš4áÇA(a¢¦#$2¦ø5&º29@q5ÆtÒmú`E€„-“QUýôÀÓ+åMÈA˜ÒPcr#)66i=\£W®m¼Zé­õ«v&¹<ê«Æѹ«•76ºó­¬Qä«!¬j5¼›xÕãY5ãm£gwËr4k&ÛÕp$-0Áª˜@¦†Kp…æƒs”lZÖ#%dWÊ#){‚ên3( ¼=ž ó¡{#F4¡e$B#)‹œ ‡z‚ÕéSûpHv’0wömÝUÇîÈ<#%(8;å(üÑz=JQø(åö¢°ˆ  éþJIcà§J†è €UDÙùûÏ·šäµ»4µÜmºîávm:ª¡;{‹…wÒiuH#)w Ø M©",‚(Š-*¡H!–°¹`$PÈLKõ¿#%Ë}æ›m­ø¦Õ,Å’²B¨?»Àù [1Ð9Òü  ç#$M~ø‡›'Mº#)0µB°0È—Šb 碆&7•*y^Ö”\9Á%/#$S1{1f?iä ‡o‘±+­  èįH=§PÉ‹ÛG‚@'í1‹ "†ØÅ¥’2Ñ“F&•¤ÆÑbÊRRLÉh°Í«EµV5¶6Õ6›fU5™e«Ť¬Ø4ë}%£’ 0¬3 VÈ‚191‚•È‘>Ì)pÛj<¡”„dlŒ#ƒŽ""w ĨÖ`³yD€"­"pȱŽ˜W#)‰bM¡²¶2"ÄI2J‡P.T±A± ”ÌC2%0ˆ) #)Š€‚«Zê0B4_P‘j "@'Íù²µÅÚ[Â¥âÍÛvj]Ó³wuõ?UÅ$LAX¢HhcB¦ ´:ÀáuPÛ\EíÅMÌöâýcŸd‘;*}žÿO¦}U¥Ï-R¨¥{#$ùB#$¢A â•·íÉ”ÈMÅìƒäp‡x#)aLv|,:üo¦& LGŽ‰®ã­ÆEˆ¡z^•ÅX Á€Ð Ùú'|ÃQ¶WÂb>,£D#%<ô¤4 i5„[¦|¡ÖP= é‚ qÞ<òë¥uyeÙSfe ÷{j¹¨Ö±XÕj]Õ¯v¼Ö"^. c˜våK¤úáýDlK±î/FS¦\¼Û‰#$$ÐçÑ~ìaöº&Ҥݥô›é#$ö·ãhþù'ç¹hQn5ËôÚ¦Má+ésƒî銜Äâž› º©ñïåëçgC(Òe"¾Šâ ö賚Ӻo#)ø½J['í¼“Õu$qqÇKž|­Ð ƲíÔžŸ£´Á/Kxâ‰Äí<cn«¹ztDNÝp·OÖ̼’—#%M‡ós¯tå±|­Â8C—n¦åß™_ù9ƒ²;Qv@&ðÍ´­cw%ôxì:´×Ãáåž›¡êÊ]–Ý™å¤ôŠ@:X·2ŽûÛ~„e†j9ôÛ½[ئãßjÌ©ªfékG»óø`0œ8”èïª3ÛXõ̪Ԯa’ºðþJºá† ütÆBöZL4’8œnŽÛ"{ìöÈ»ï¿Gø{æû9âwlÒ6Dá㊠†d"xŸ'¶šém½]Ôw„æ¦{n÷%®†¡ 1ååRn#)Ÿ¦B_Šsƒ#%¾î┪ÙçÏèÌm-ü¦Z ¡¡‰ú{ø¾¿EŒt^,Q”HX¡TóZŠ•#%äAÖ(:Å’û©Nˆ‰ZîñŸèŸI¤¹Gׇ%w<´É?}‰ÒÅÂâa@µZ–¤{®¿Ô;ai­Ã´zIzö±Ì¨ë¥^_¬Œ¤¼3¸Ú"šZb¨ŠÝRÜiU³ö¹_ê}9nwÐi÷Úýþ= lªqÑh˜êCâz©9ªÈK8ñ i¶Ù{,UbFá3ËÚ¿#)1˜v-¯´pT¯!Î~×™ç8[¤"Ó=’ï~tÀá#%qQ½s%1Г¬>ÖpÁ¬Ú‡àÐÊa¨ÙvßÖ#%åÍg_* ø~b;M­®™œ 虘¶â­÷kÃÓ[é“áã§f´ÈË€çVè‡è·EA"dôð’I'wEœæy­Êª3o:,OíE‡@‹´o¦X—cÄrmLÅ1:c-ÛmÍé8â^Vm˜Ö)Þ¦Ä0`VŽ#Œ–áå5³…iÇüÄmŽÞ$rïbsLÚ§ÎñCh¼b9´§ŽÇ;o­n‡Ûû×]ÎОeä’yxÌÔoQ&ÚxS]±QãX‰éuðì8¤9dÍB8‚µ³Uîíä+4ñ{꧚öª¼æ{Æ‹ü¨äÑî0‰Çµn[›.ÜKc~H¿_'ÂÅ-{¼°^9ÌŒpäuzó|‡;þi{+*S¹ç/ÍÚG~Iñy§Íóóš³{É=/Þ’°p^WÛÅ—•zàœvx9ÜÆûW:ñ×c“Ó,ûfkOD»¿j<Þ‘(Ú#J#m»R­³žS‹ )u±lu;t#%_8Ùü*aª‡}¿­˜ÝJ<z&ƒ/„Áí7Ò¾÷”­?—WPÄïcé7^“ïéÛÓÌÉ߸uíÐ1¡4dEèÏ7Ç”qÙcPƒ¶å¬mÖœƒVp¡Ónåkw1O“ÒÞBm‚ÔRôœåÎ¥ ˜ß¡Mè,¦îlänÃÏy5SC#ŠPÐÞ´ø ×mÓ$a[̲Ržkô1½Ì-2ÆÕ'À‘‚9'Ñ—œ>Z‚š@#%´TŽ¨_1Åéª* #)J®œKÂÄÜfŽ™ìuLòW^!ŸÍw"㧖 H7…é è·òÄ™*†„&HmÆZëªê$æ”)¡ap×Q6“3‰•‡…Ú ÊËeØä\0È.#)tb¦qÉ##)Q¿¯×¨‰…Ô bÇ-H2€ 8á¹:>“öáëÄ-–4K³hò’Yr ™ŽA ­ù¦`ÇŠØ/lÄ­„†Ý$ Ü5R(ȺN¦ÁcxKÕANHD¸XD„Q0@H-†øhŽFMºxW^Þ¼qË;%·3™BԳá #)Î(çÀÃ-ÒIÏ!®£A25ÁÃ3Š€Æ‡ÕN;_/)¶#$9ÀùÄqA%XlÄÁÉá#%xQGÛUk挂k”P¨cX‰Hú&š(‡Q7è¯#)ˆ]4% I*PQõ n˜ªdæHĹ?!Q.×ïˆBí®0¶#)lq™S¾£Répû¡ÛÄúÍF6ž'ª!mÕú#*=Îm…Ì¢DGh´®ž!-É–ö’Åßnúª0â[?E´÷ƒà»£uk]ºcb˜ƒ#%±7¿`'¦Â0 AãjÙú›üôu[ÚW±9LÎGÑʾ:ÈJ‡¬!˜€²ˆ÷;­¶}ë 8ãÆòÑpŒŽe¸©ªÞBuNõÒ²TB<FPúèpKRÆmàJ01D‘šµ,yñ)l#)ËOãb¢q]ðø3<ïı(®áÙô¯VðÑ›Ûï.fÜÂN™¢¸­b0ÊV3õ¹iN® ÀùŒ‘ÔçMɾÝ6+³n9aéÇõ¾b¸ß¢ß¾%#%Ù²Lºã–鄺£6Í¥“X.ŽCkâ^Õí¾Aþ¼Þ=ãòç•ön¥˜-ß½¹å/ºí}ãW0ÁækŠò—KxÊ–¢aF<wŒÉ“²[y(ê§ÍÃsq yHï·Œ¶Ÿ=ÁÂx¦o¸fù‰/CwÆÎ3Ê™[V¨W<̦É{x09b%‰K/kKV%¦CîÆûi=TN*PUÒ)<Ñ,ûqÁS.•Ì¢É)/…@eÜ á8*jrbñ&°Tù‘æc!¢õ—tyÑ“Áß¹“ÍÎOÀí™-üY п6 Q‡l\a0…ëN6Ëð‰¨jœö£°NYqpÕ¢ð.XHSE‹8-²8‹ \½³Öëdyfgœ Ê9;ZØXm@ljae‚1™áCÞÕ²©«¨T45à£È¶Ÿ^3˜{©V“PØò•Ü5M(P˜3iA¡°€T‚;Ð8Ik#´âÆMûäÖï0ât#%GT9‚Hð˜mU’&÷ýÀ×]õûC–6¨a²l#%~ŸŸ(û}Ä-ðjÖ±úìÔ¼Þ‹ºÜ1ÓáÙ1ð;l›åøƒÊŽY’ ¿Á¯1.ªx<KÔntùw\—Ë<?‘‡œ<¿Ãû—W‡4;ýaë^ÂØÈö¥£HQž^’øCxCìC`ð8»ÍÁÇæ|ëkŠ)R,ó¹li݈ÕûY¿h¯m«»ÄÁY¼æ ìЭ#™¥KF™@¯#Á¥|kÅ×&¹8u]Û;­Þõy½¼m½m°lkåÉw[–‰/(¡–bH…›ÀP´¢¯|P*CRÛ[Ũ¶åª6Úæµ"#%±³¶ ÓEI96Œa0 ¨2*"#)¢Œ…JrAîñ¾rñ¯ ã¿b¾Û#)(PC€èôgwcTvºÕýÎ3Ì,˜Í÷o¤D¿bq^¯xÛ‘pƒ)T<¢$‚‰  U#$2 2˜JŽhnßsT˽>Z¹Vð}ðÍ}·XñËe£ ¥¿Ëâ*Æ1ƒF(©QL¡ÎùáF–†àA¦í¥ VS‡þ?Ó0lál‘^#)1¦™@ûæ•\“v#/SN0Á*Ì<òº¶Ô#)RÎ|óM±A¤+ ÊB4È¢Äpùq§©àË#%V®ÈˆÄìÊò”Ä5·€òJã0‚j4›M¥Z’)a.UXؘÆ4C)[ÌPåf²Fl²‹XT±‡tÊ]$…Y/O¬¶áí6 ŽBîMÕˆ`&j4àÄYeݸÅ5en°ÔMÀ(Çc^Ç{8cZhëŽv²ÍîFjh£MÔU¬zkZÖæSÇ‘ÂåËÉÆ.3VÊß ˜ƒDE¨ÝŠiU €å ªÅO.QÖ\16Ô³‚"¶&s-~›ÞµÁoDŒbE6ÈvÎS¼ÊΘ´Ø&0‚9Ü6(JR#M#˜t³LÍa¦uŒˆQ¬aNÖ•§¢C›#%,ªoW2¾¥dÉJÌ$»ÖÇŒŽ8Lº”UÁƒcrz¤¼}âµÍ#)D‚nKÝÛWm¶ñwfÐ#PŒ{Se"r<”+C׉ÃVñCDÒ41œ¡’±ƒjÚ7 ¥PT¡V·š#%&#%¦#%ŒM0¾5hÛÖâÛÉ’Ë+·®v,ÚØM˧Ƃ „Øh2‹…³wdeànkh0ÕŠócºlÐB²d)3É“.ßë9/ ZËß`xïh\(4Œ)±å°~Fœ‘ùÉ{*7ÚW¾î‘05½m±³¼Ã¦cØRDØÛÞX5X20q·ºn …°¥#)Óa]`wF:ьд´yÆpa;ë+`æ¥5J©XùyN{b¢ã™Ã&FÔ¡áYUVÒ5‚‚§ûl(ñj>31öeIÑðV"Æ…¤Zñ¢×ÙM#)/ i Çn  çaÌs)Àñ¤™ÍmÖ‡Ã[zX[2”ÀÓ&¤0ËÇ’m£EÀ}ØV®n`L3ÉÜ$g>»YŒŽ§â4ñ¥¶Å³<e`æecUyLjTËlÉbFÐÐĈÅ=Ó9HÒ TŽ,„ Î ß}f&º³ Þ °g~ 8¾d΋Yã/z»4vø¯[ØãîõËŸ)TÔF‚‘)GaeÝÆ M¸ñ1Ÿ0áîÿ1™^h0XB4O!}+J‡¡¤¨!$/‘¤(w"õNùP€}Eàœ‹Ñ¶Ïd£^É^Œ2(ÓUÚA܉Q‘ÁWžßB…ö°¯‘¦Ü'éqº²±eÓ®38™~§WÔð~ð’@ßõz5ô @N-²I›ü|ý?FÃëgJÈ ì~¯/^zx>zH10öœœÙ¸›ËŒp~¯/ÜKütuŠ#%–ªW—)™óñ›ÜõÛá"4ÝÒww&#¥ÇvèÈʪsÈ3<Ø‹g“ÝÆuêNÐ÷">ð:ž1pa8¡I¢«7¶Šjä~¬B¤ïéêMMÏ8;ú>Êš–Š€'qU_~¦¥z71µ²©”ÕhXªˆ’…´EK-H/@ïýSðQæD6ιíî«Îi$ BB6©QSIm¬(,†#%ASI#%TÊÙ¦McY5«J6Ä›IŒ1›*,i¦Í4¨Y%¥’¢(bšƒQ)Fš)š6M†•L- k 6aB‘@d$EOÚ_¨ó•å0TNX³‰Õ´LEõÄ·oDìg-ÇÛ7  ›.f'·p ò.†¿« ¿ÀC#$M7‰Óèí¶ÎFïMŠIð—VÐO0Ì(,‡…èY$C*‰î –ÊAça@mI¤wö›ð†Œ]û8ç#%0ÒMM«sàã:0þ¬xÂÆI#$Q’#µöm‰o7•ÐsÛԥȨ˜’Ä.!ºòI!uFšÞþcÝçñÌ}Úó7‡>ÈÀ½U âY®¢FøèÕŠZìs S¨`MçôÕ~µ~£m£%lšÄE¡”F©5¢Àµk›H¶Rj1X3ñÝ«™¶Ê¥å@)T¥,…”sà Û†•ˆHÂ¥ !GßìÌ.#%eYl}Ö^ :{ À Ï›h…Dv‹Xiâ0Üü™tj±„>—gCµEh¦¤#”˜ˆ¡¶ðrA¤E ºr’³[0 C,[ ±w$Ã!l$X¾C2ØÁTF£CçÎ×™F2”íïšù•îM…¦`1¬iG~¸³5 £31„JÀïy”¨XÄÄBŽ ™‚#훞4qÓM'øÐj%3äá ÉŠC’ ¹rÌiA$yàˆ`Ìëæ!r6ÞÞ¶» ™‰\µÄ›ÞÚú_¾'÷Ó•`=Ÿ®lG:óxÛÍÈÅ*‘ÑÆE‡}&™ XCµÌ¢L“¸ @ç0H ¡#%ÌÕRÏ[.¨T”KšB€Ä™ @ГBý¡‚ª³ † êßѺL#$Ãgšb¥*‘$@ èël'“öái¢¶oÙë›Ïwo>œgêJ‰å(lÏ Ðõ‘! ýØ_ÔýX“¤ª°lyy•ƒ.j!ï:$ªŒ¶\°\j¦Û À}ŠÂRЗ0A†}µ#$»¡ÛÜp÷ªüfýú•‘¶ #%ÀÛ:-«Ó·ŸÛ5j»j2ZúÍkï÷ü3M±±ßwƒD³žÁûÏ…Œšü#)ƒ­ùF“© iaáñm1Ø-ƒ¸Ë5üL?mJ?² $>%JL! Òjw‚g7E$,Q“bîŠÛ%Ö¼åiÈ1ÒЋêôž»‘:|C‡¦.Ä6WÐœ“•®J4óêFEªèÀÆm{I ˆ2/yÏRî;¸ºÜ»$Ìô|¤Ü»b&pù̶ù)s@ïJHRr=F½Iþ‰›ó0l8Ü`ð,ív»Ëêâ„“6z9ˆ¥ŒLvÕ‰²ì Ø%Î$$(’¾ÿStÒfê¡‘00}»~„n„†Œ=;O·èw°ˆEAI"" ª—Ÿ¬z¶©Gq1/±ûu»cETÄð¡ÛÉÂHr ™ö¯¬VÌ~WxÍ“ó«¥tN;ÕK!UÓE†1‹1ãvTÎïÉ z!ºV˜<L˜ŽEa§´õ†ôíª‡inÀ;½‚ ™_/­ÛìÃx`¡ŠÒð†tÊðÖç¾°çkxÛš9/Ælèã:ó$g,!`Øé©=f)1é¼ÎŽR¡$i©ü]ñ{c…H5áä\]ÂÃ>,àD¥"O3OÃÆ3YÎú›í”#%[0Ñ#$po4DhÀ¤FÀ;â3"`âPHšŸÊnªÄ°dþ!QPÓSœ‰0|ðÎTS]æôofø#%d3œ¤Ä`$™PƒIÌV\€!8Ã%Œ7iŠí(£Ja-4ØγB#$caé 8 œ@6MSg~5,3g«ac\d¡ƒ.— 5ß»y¡‚ð¹–uÇÌ°·#%“zéery06CÅ°N,%D‘#%h¨Œr¦§™ü  dbišcBã‚6 Ñ‘vEyH÷‹#%àh͉*·ÛF'\kÛÄMª„À A$‡ ƒ ,N‰ÝÜ`ãŠR#")7BuÏ}zèãp;몕¡ˆM“', $jÚf©Ø„$3j °/P`Ê5Qçåþ¦qÆë`}ºYÉ¿ŒŠ‡v‚L!Sœ¢Y ©ºãhj„SºÜ‡"(3Š•æ¶Å~ù„ákŽd3Ç7‰®—†à]`™[‚KÏ}mÙQšÃä¯M»‡NJ`–t[½C‚í:J(7f²”ºÆyª/¹˜S#nìżÌ3Θ”J¥¯4½i Z €c#$ ½-`•‹hl@šh8ï#$ZbÙ×5s#){ÑRã¤#Ê*I·‡™òŠR®,,gÅÉ57wyÏ›¬ÁŒ«ËH<fUß„¢GšÁi‘½ÔË® —fZÄ3åãû"‹–^9Óᇉ$YXß*+ ¢æS4 „×i#%H#$ó!œäg¬$eìÊ3 ìЫåh0(‚k^ ¬â#«ÊE:§"§u×n؃H¤Àì'~tö\bIIeñ2dú:ÇM¬ØÖ–DùG$»h·b¸EC`LBzáƃ-#§#ìƒ:²¤ÛnE-–Eî9€€Ý%Âj„åH«j.·Ä(Ö¦EED&µ+b%7ôjH¶BE÷wʼnžŽ3ŽÛ‘;T_W…+ý¢©mz¦Q u$À“RK Ô#%p%&™2;z%³1a.¼‰X>uYÃÄxW5­¨´MxƒwÙ…›jnªs¼7 ,SìÕ$k¼1úÎi¡ð–-uy繜gXf€‰–ç®u I ÉR£‹ }©¯§›»\Š~EªÃ“,ÏRæíLL1ÙK9ë×G®N#%tšLšŠÄS(ÔnÌHÛ&l‡í¹Žx5-ò陉Râæu³‚À8âÆUÓ7K¬áåß‘ :ì2k½¸)òJPàpêûè,Á™’Ôåš›“HaÒ ƒ®†a‚Šca²ÓM‰#¦©b,(B&’cC¼)ÃSŸº--Î(2Á^ѺÓéi"è®’ 9s¾#);ʲUö’Ã<] sH\­Ê9ÀcÚâ1®®È’“‘Û¿à·Û,iÍ>ã5¿K¢“P½G#$¦*€j®5ožÅ±äÙ %ÓïÂì-ñ†!DºZ:ÙÁntQÓ6‘Â$üoöùJ!í²æ\6E.@ZòXšh?¯'+o;o­0Œ€„#$ÀsdìM^ðk¿>%tÍ« nž8ùùÖ¸cDsM|y’®/O‡!¨ï¦QR§Ðai¬½žm£y¿!`L°º²RkPC6 JbÍ;ËIñÓq!-oŒÁ¬,¥C´:lSCòÌ/ÓÎèÀ娘ˆÐ@m‹˜*ì!ÀÌP•:OGë´´¾±˜ñ‡(It ºpw¹—ÌïÒ]»;uV­á#¤ïȘ}^Üq“#$…³Z«&7€pŒ˜Y#)Œ%JahüŒègÐjòç"¾]•ÒÍéSfÍÑÍ"­¯«Y€kyLôgÈ‹ÎIdx¥:Îé𖦥59ç#†b¾%ÔM#%ïÁ@áƒ='<ᆎ:¢Æ†0ž9¼1âgÓ²cM÷s1Äo¾PÍÁk±4 $´òˆöbîó\U¿ Ä,Žt˜öÃ"Ù¡n${ ÎŽÄHÅ S%…p@¸fƒ8¦òCi¡›üc„6ä„E"GņdŽ o¨a¤‚+Š¥#%“Y5;¤ÛÝyàët÷²Ñ9%1«͘(Á7a†Ù¥»(dÀ`¹˜Ý‹DÌ" #µƒ)Ê3+‚Y,#%#%K‘° ¶‘q\] STŠŠÆ&ê`d”^Ë%3¸h³Ëã|0…Õ/e—o™Ô«ÊÓ1¥±„lˆbßV•\u9º£(в Ú¢ ÙÕ‡È͉£”Dž¤H14Þˆ#HaØßÍFFHH¨§#@ÈÀ#$Èv%‚\¸ê˜˜šÖŠ¨ÕѨ›3€Þà¡P›•#)Œ#%Ìkb‘À#)eç+„3œq»§XÉHg8i¡8ÂB¢ê™*L"ZBÃÀ8¢ ²}IåçÒ|L{(¨4´TDP;qšîEÑ6ååÓ'¤laíä@‡Xhˆ°‰ 5#$¨Aû÷ÿ„·–ËØ>G¡ãìz›Ü=Ë6Rj%×ï+LÔßi©Júg/Ð-#%D±¼’9tæEî /ÄÆôÏe1mÈîºVáÃa7K¼f$ÐÇHÚÝa€Cj —¹$eÈbŽ&ß™,W˳šë–µyUAéµ º29K–Šë¡A7ÐgꫧLJ”QL‚lªG„Màö3]¬ÑðÛ½4ÉÀx4‹Š”µ#´¹DMøÜ™b†‚dçVŠ­Ô>û,’û ­d}åh/¤‰¦Lžî¹wl~ \ÐóìøÏ&~Ö´®¤aÀCŽVŽsJ.€ZõƒˆòX›/®ª­ ¯fãs½5‡Öõ©Õîó7PÞ­ÝÐpÆ#$H_z_|þö¾à#$Hˆúèljï>Jt0Ý"c\ŽWÓd{öÅT°“ëŠm²›Œ\z~x¯ Š¸Bg/­;µÔ^W¥'n‰Ý.Ûi‡oyá* ㉼ƕNÒYƒRÁ½ò9wmy¤„’Q¯$Ôï$ªDØÀay`˜Øì! d…(…K–@„@¨¶XÕš1Q¡Á Q™÷Rd+#$ñN×ë$ί=Üs}õ±Ì&²š24°L0ÑÈ.RIðœ 0ß<ÝG_cëíð ì˜÷ÚkµCæQ:¢ À8„Æ'ta“kÊKUdFwV‹S¤‰JF*Bw332ÌAQXDƒ@å0¯> õ†ÐÊ )ú†Ž#)§¿ÔJ#%å çæ`.‚›ØÃWïk9õ}–sì4£ª£JzÑ›*¼ó!d?qAaŸ/y4(ˆPø“„Úð¨ÆmëNzkÒDårFNþë/X/ËF£UɸÀ¤Ë–q™oµ5?TÌ›rŒ›¹aâ ¦0†° §¶=#)‰~nx/G«p¹&§#)3pfédø]¬ ÙÆ%7r½€?ıQˆ¬Dô ¤ø›Mm›d5ÐÆŒ 1­‚‘è_”¦DõÅ*"{` E%²ÕiFj¢Köed¶£jMQ­o‰­“m^ûn @¹Ò¢€ÞØYV¢H)dˆ7HŽ P"@X M€¯d@v€"ûokqÜD…¯÷h#$°#$c&þì?L›ð5øþ¯o»}­bÒÍ&ŒcXщ¥ïßÝÞLÕXêg 2#$ýÁ‚€Hˆ*$Š¯Ç#%»}¥÷÷Qã`¬óë7!݆=>òt“ÜxÃÓ߸[1F1œ‹à1§˜ 4a¢L"CM£2XVK’ƒaD"ŒTv¢DÈÛƒœƒ#$Š´ˆÐÚPrP¢BfRa ±#)‚í£ $â'Q¿K£Ž3#$4*:éŠ#)»€,-(l¹‰f‘²½}j ØzcØöŽ/4°À„Â|×'Oà}Î,5¶XÐÔæCNï…£gʦ%ccU ºÃ¯¥°v€l )rÄ‚Áˆ#$¡±×‹#%ÄEàb 7ü“´D“jÉRw–¡@$&T• Œa„¢ïih/|žœ:C ™g†¹Ee#$Pf¤¼r!Ex{2›è$Çml”ëÔöoÆÅ!#%ø™>ÄÍÅ÷è²mç·#ž¦ßw!‘+Ž]¶­6Ó¯z†®&â¤;%¼6WËvrr?&\Êᶈl‡ÔS«¾:eOQôzÁöE#%†±A=…†*A ÓMZ•A†[á#%u%ïé!rKïl|²êO¤ò;Wݹ#È çÂÇ¥e­ÊË5$©¦¢cAm[0ØJ„Q³ZQ­R[÷”V®3•Ò@„R‡s¼ßlñj_Ùˆvè®ÔÜwtM½ó7@<îˆqðÜùˆ.K­Ý³Ž#%`!¬E&|ˆÙ=‰Ýà:õSwPˆu¢w©ì}·#$ä,Cƒ³£RIƒŸÓáÓ²('QïÀ}ulÿ  =$4KŽHÇ×,ŸÓÕ‡|ü☣qÇH¤A¸ó½¶’a©»¤îâƒ$ã,%»É`ùÑe®,§DL\³–ø…héñzI¡Ô\#hÚi–Røj'»uM°t‰¨gCi¤iKb Hm‚bÇkÍ<=\”’e>³§|%Ã;í[T†—°€(,´±%Ô bÊ„Ì̲ÑùµvùDMçrœ"1ø} Ì‹fȃä8Vqª:6bßæSXˆ.^Íínµ‡'üKêŸÊÍá$‹¦GNËôÜ´&$C«¯ÎóÉa¸®õݽ@P)eZ·ÉA.¨ú#$B§.ο”ãa.}FÄÈ4“«#%1艂dA¼O0@@#$UR";^¨ôñÁ7ûÏmï»àP#$Wq×âw†(#b wIT›N‘J0½aEF†½g°“£Å‚BBq;L°×}ÏžÛü½,Vì£.ÌgÚ3¤t(p›«‘²QHV„Ö½îa÷l#%Ýîùiäµd#)ÚˆXy½C^Á¯ˆ§`«7eŸÐ‹ÒMtéô÷6ê¸ví¢åU¨v‰Hczì—n^6÷ÙCGK¹Žkä[í*¡à#%Æ…>16‘rbJ;ÕþØM‚í†'_SVkËïQF™1™<W*+$»µØÉe}ÝæA¶+÷g=òóËÞãiÃT¢›!hÅ•äÝd#)ò6Lj6¢°†1–êM©–Öí¿™JFÄü ØD6ŸîËvߟÜxxÊ((õî‰â`|,ÏPxVšALGÎkó_Hõ*tõ‡_XH²+"1F2 Q‰'¸èO0 hxÅ £ €ŒDeŠ™Z,–Y’Ù³jüÿ³ðj¿‹¾ñ¤Q¢ÙQ¶4›JSMªü»oåîò„Ëæ½cè"¨TDÏë„¥­¾Á™—BSÌA,HsHNt"N£ò`¤ÔL#))TS")±Š‰µ–ÑE¨£ilÌ[4iïžyª“V–›RŠ']ˆ„]àä€a~P×þOG-@õ''Γ€$íDM ‚sÔQ¨#}*ið‰SK²ײá 1>A‹{by"À‡`i€p@Êr2Êaˆ’éÅ=ØJ*½Çw‹!I ªNm'ШW®>Y˜’ú)IFw B$„²~7'-=6#)Šî€Z³#%^`:£ód£ê²&"‡4öP A}Š@*Rf6›#)XZ“k›¤µSmF”š¥´ •A‹fÁRæ­¶m&#$ª¦ÎA]”+óê`àJ”ÏH€H°õRR÷jc×Øméªêù$Ruc»Q”ó—0¹{=9¥†ÚcÐòø¨[:gÒ‘°ü”+%3OŠK⤌‰C¬­˜¶Ò”qÎ.9˜ ~ü;»šãùêCf¤<ö6¡ö›écÚ>åóþðÊ#$”d4g…HÓ’#FLJ’4FXÑE%Dkc&ªÚ7ï+~E¯*mA´•¡Sò~RJ T U#)#ð‚ŒB~`é“v @ª‘ A‰‹#)<¨¦‰Ÿ1­ˆX)vêç{çÑë·d´×sˆõ"ÛUæ´[QŠÐZ”* µ6X‹hÕ©¥¬©~©µòôæmògnöÒ«,”4åëÇíTûP¦S?Ë3…ö1š‚ÔA#$e ÆoÎœ’Mþʘdú§!» Ei).賋kŒ¶!´F8•$ TgyŸÝƒ°¢‰&ðBÒÈ]@¡–Ñ>‰+Mƒi¢•5îl5ÊZ7mwvWy¼­uM¢É­ê®J‹y»¬ÍÙ™U×7mnuC5‘e«Ë»¢mwuwv´›*L˜ØÁ¤ÚCEÂD•8)V@¥DŒTm¶Q¤#%6âÄ[Jilš“,«•®­åÕמv¶ñ¨¶Q™•e²–¼›uwn²Æj˦ºMÍN¯‹œ4<Òb2B¶Ä˜ŠÄEË‚ý#Ÿ &¡Ì’pÐäM–%ü íý¦‚´›L¾ug´©­]ù>o5û|g3 tR¡úa1T,½ø˜1©›$™:¡@ÀœÉÇ­[Lànw¡™Ý®K†b.¿ã8eûp#$0}0’ì$œˆöwêž|¶;ÑXE!]7»“y<´œXÛ8ÓÃ;ñÑí^îã~07"ß_ úAi‘‰1êDÐÕ)cS{é[§#)š`SS9¹„c }^FfÌ…:³ë·œA¢Ž+”R3‘x\ëÔ˜Þ9„þkÈÁ%Áæ1‰¢Zmaãéç/ZÙmÝù줗õ‘Ñ™o'ý"Ö±ÐéõIZGJƒ×[ë õCHbyq• -…-Q”4ÅHÇ¿å&{$Õàòí¡|šAïŠÊÒ#Zi^ªŸë7#%R„¾ÍûN¡¾;Ž¢,é‘|þë{öLͤ$~zÄE²=z’IhÉ‹’…#YÂÂ2“p錦-*P`šl.:3m30À5q=iÔ& ›£°5Ñ—@(Bû“'XYŸ7käN% ÝCd¸²&)vCÞ`‘l±(´ãWVW¤Ý=à?ËÃó@°7­Õ ñDĸpZ¦ðËò’ 6Q~ˆ§„ ÛsCãÁ–ȃ·º’ËŽxFêßë¡jIb8j«Ûäe‘R–é^Ó³2#%ƒúdf•,?Š*Ûr½Dæv+åV¶ómA¸(¡“ü4,ŵ9•Ò‚k̃#t[Z…]»Ó‡G~ªÜØáÂ\#)r£}÷C“{QÑ„îr§½{í´X q8p–hæx%þÄÌç†b– ¯-.9¨.Ã,¸ó£Ìa‡rM¶ Ó‹~BœN“xó$ÉôKšžg·é± ‡I¨ñ>iÄ*ü/³Ùl»Ì´4õ]1~Ü „O¿/~+pAÎyR‚¸@±HnG«N9hBÆÚø¤v‡„òG¡è…ÏĺïݶÙ>U­Lä¸+“ 粫hÿËÿûûêÿ/ýýÿù7ÿ?ú~œ?áÿG£þþðÿ‡ýëÿ“Uïÿýÿgú§ðÿ¿þߟþ?ò×þÿû¿Óðúú?özôø¯û´ÿúû¿ã§þï÷ÿŸòÿ…ñÿ‡ðÃÿçú|Ÿé»þ?/ý¿éóôÿëåÿOÛöqÔ¨‚߽Ʊhü@€u@íl€èº•pÿ)ýÐ@ÞM„Áý>ö T#)¢&B€sUs0)*ÿäŸß¥S»±$&f}ýo®Ùm~·tJ#–{rôk¼ »´Ú!®<ÎHTÕ5„ØàEÿ轤ëïß¿je´Ì.l‡ö‰noÝn*j˜=ÑÖµFIÊ:ì+¾H1 ‡0Z¾Wf±‹:× @¡C×ýªÏ#%o™ä§üþ–Lõ3øKþn6^ƒb9u(ðÔ˜ÌiÇú¤Þ* L„‚ÓI }}Xך«Ã”ä’Þøïíü5ÝòÎ$|e­1Ìv±•‘ž#)Ù™þÇ``ÒUÆUTÚ”Ï#%&QFišÈU4Ó.I\Ã#%ŸúphÔ!2ªx´o[R¯­4‰—€ì`G… “³ºÖîN&ËŠ¤ÉÊX!l– ÷4óCMÚŠ;V©³n¬fõ6ÕÆ´8˜Ì‹Xqvak#%í] I˜qx“ý2Í…’îHÁ#a#%pÛÖ=_b°-9¼R6wryÑ$´¡Ý#utFò÷D3ÞiÔ=Ðg=3YGýÍ„e/€ýß 6P®.f,‚Z"fVHÄb×/;bò#$c.Ð6‡í|mÄÎTcæQZ§ðHuo ‘ØáÒ2jǵ.cb¶*t\¾Üº·ýjÄzÿÕ@ÐeAeÉãÏgÍ 5æÞj¦+¹%Y‚sEŠD|i'‰aêõá.áI9C\¯0ÛÍïÜømà kÁ‚ª‹IRŠ]üºoè?hz˜ñÐ,g35V#) yâˆ(RcŸ»n)Ù·S.‰¬$d]®épÅC(ŽÅ€#)ÈÈ ;Α¢üìØÂH b¡$cÖ2âï(wä¸Ëb[ØAöýsÄÌá‹ý’uÊÉ€Ÿ8Ü—ÊÎãb‹&#$œµ¥#~F¥»9Ö‹Î0•ssIVÒ‰#PÞ.%D¡¨*‹VR™[bÔ–¥4ɉ5öݵvÔ¹eH'D@Àˆ'ng¸ö‘ âë"î‹1áTÝo0PE-‹'CØPq)¤¬Qg?ˆ|C˧”±þùgù­ãUh„ßc÷CCþÍêc“Y¯=˜ŒPø W>Ï8Ï/û|6iš·ÆZÈo´ÉÛRÆpÿö_ÙCm¿¤f{عe|1È·Ô{:«SfŠï­Io‘-u#$8cÒ"ñMòiéOuƒö~/·Ò&‡“#9Éf†P4Ò©£Ë3|½’l{ŽÂ}4Xj!>z˵Íãt¬m–è¼e¯«Mëò6[A”¥4­Ùap†„±o£[ìnÍ~½Z@­Ísi6£mËSJŒo·ª6øV·¹ڤіZ mó•\Ä™d,Öì ÍZ#)^ðJcvPääR$8ªbcþ*S÷—ÝÂá$$Fàn1t#)"u:»l\í6)… bSß·i%ôì™BkU¬ŒŒôRѸ(;ˆžû§Õn¸‹˜œ(4’,€HÍãà)_ö^Ãçî£Í“ÐŽÔs}\EðâQ‚ú˜póÃUþ¨‚À ¡µÚŽã³@h’”* @W#)ݶÝe«îh›5&½¾ÍV<¡ H$€ #Šöú½žìœÿ_@‰Ø„xtù@òþw®c#Ûmh‡bÝÑ::1O(4AŸ“Ãêûƒðÿx…Oùõû í&Æw>(YÿÃÄ”"×ýÓn–ŸÇþ©ÿnþ‚©ç10…?û5ÿõ´¯M»Íy…]¡,Yû;ŸÓÿËû6^U÷xzþ»6ì’|×í#‰Í>xð{Ç]Üó#¿ÁÃÚÈ@{òÂÏ?†ñ´‘ì×þº‡Ÿ¿€ÑÿP‰ÙóªyˆqLbøá¥áñ—ŠåÊm‹#ñìÅ×þÕf2ô#G3عBºi³GÿŸPŽ¿2¨•˜ŸéœÖ2’ïÙGí©Gþz-g¥vñ8ª"™Áתáq–s¦ò8‡ÇÙ´éÛD è2²±û¹ËxFá‹Ëa,oÃÂ4N*%¯+iÌ$]ÏNyfαb‰Çz«ø½n»2X¥ë&¸ ²¼>ßefcÓžÆÞGi={í>Ÿø«#À§œgPÛî1ë–«ÂO@uk§øõÿÄc±üÐdcù?_̈ÿñw$S… 㥧Ð
+#<==
+#-----BEGIN PGP SIGNATURE-----\n\niQIcBAABCgAGBQJXucfbAAoJEEm0xnwFJ3qq9HsP/jfAbxzLd6uHMfpZP+GgGJeY\nDx/t+p8lKI3r7VDXLB4UkzljBisNG7/uNhHZ7FB86JVP9WTKOjkRk0a5GyjBHI2K\nNFBxC/cUljiRs+2NA72MPFUkGJWG7LFeYihWhpto5iNDGtyBGxYOn9+wlStixOIP\nVVbRkTxc2Pda+Rwqj3zfPVZHXWxv1kPWhrLth0Y/20Q8CBVa9QyDK6VoXgBY9Kr7\nOhijnsGAX2R+CVfR4iCM5/QpmJClWb6+ER1bPrvyCdTsCzOZZLzvw3+U16YYzrGK\nWj+PE+Lfbj7GizItZSB861BHcl9yGWd0p7MxYoN8tKZljTKksF53r/QXm2JVkUCZ\nl6vY42scP3tThgyBU4OImokEfw5GY1JbaEtzi2sB7bdzcMVgTCWrzozJYqEXXGlm\nPY9Xsqr8p0YZT6T3l4vFAAxoNZ7vBcyxixiOzkygX789/vHurylRBLsH8uSlMt9O\nqRPEV+c/NzzfrxKPlfjvX7Jzzh6Fdd8QzLheKE4skSwbQ9Tb503wral+tPSbKvGp\ncU9PWFlB7W+TiPua+XPg4wkA06lwo0yhDH5wgLme+LkeUaQjHo6+MCweYjZtSPai\n/fAre5LUhHrUpWPogvWSSdq6eK3m76utSSkHCJAj8mvhTWV94A21Rv6dutRvujKo\nCQGdw9yT22XvPzQZ74b4\n=lYLz\n-----END PGP SIGNATURE-----\n
diff --git a/doc/waf.css b/doc/waf.css
new file mode 100755
index 00000000..81f019c2
--- /dev/null
+++ b/doc/waf.css
@@ -0,0 +1,45 @@
+
+
+div.tableblock > table {
+ border: 1px solid gray;
+}
+
+div#header-pic {
+ background-image: url("images/bg4.jpg");
+ background-repeat: no-repeat;
+ background-color: #cccccc;
+}
+
+a:visited {
+ color: #8A2908;
+}
+
+
+div#header h1 {
+ background: url('images/trex_logo_64_64.png') no-repeat left center;
+ padding-left: 80px;
+ line-height: 80px;
+ height: 80px;
+}
+
+div.title, caption.title {
+ text-align: center;
+ margin-bottom: 0.2em;
+}
+
+div.tableblock > table th {
+ background-color: #F4F4F4;
+}
+
+h1, h2, h3, h4, h5, h6, span#author, div.title, caption.title, div.admonitionblock .icon, div#toctitle, div.sidebar-title, div.image-title {
+ color: #333;
+}
+
+body, div.sectionbody, div#toctitle {
+ font-family: 'Lucida Grande', Verdana, Arial, sans-serif;
+}
+
+.monospaced, code, pre {
+ font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
+}
+
diff --git a/doc/waf1.css b/doc/waf1.css
new file mode 100755
index 00000000..7255051a
--- /dev/null
+++ b/doc/waf1.css
@@ -0,0 +1,78 @@
+div.tableblock > table {
+ border: 1px solid gray;
+}
+
+div#header-pic {
+ background-image: url("images/bg4.jpg");
+ background-repeat: no-repeat;
+ background-color: #cccccc;
+}
+
+
+
+div#header h1 {
+ background: url('images/trex_logo_64_64.png') no-repeat left center;
+ padding-left: 80px;
+ line-height: 80px;
+ height: 80px;
+}
+
+div.title, caption.title {
+ text-align: center;
+ margin-bottom: 0.2em;
+}
+
+div.tableblock > table th {
+ background-color: #F4F4F4;
+}
+
+h1, h2, h3, h4, h5, h6, span#author, div.title, caption.title, div.admonitionblock .icon, div#toctitle, div.sidebar-title, div.image-title {
+ color: #333;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-family: Georgia, 'Times New Roman', serif
+}
+
+h1 {
+ font-size: 24px;
+}
+
+h2,h3,h4,h5,h6 {
+ color: #f14e32;
+ padding-top: 0.5em;
+ font-size: 24px;
+ line-height: 44px;
+ font-weight: bold;
+ margin-top: 20px;
+ border-bottom: 2px solid silver
+ float: left;
+}
+
+h3,h4,h5,h6 {
+ color: #0388a6;
+ font-size: 18px
+}
+
+
+p {
+ font-family: sans-serif;
+ text-indent: 0px;
+ font-size: 14px;
+ line-height: 22px;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+a:visited {
+ color: #404040;
+}
+
+
+body, div.sectionbody, div#toctitle {
+ font-family: Lato, proxima-nova, 'Helvetica Neue', Arial;
+ font-size : 13px;
+ color: #404040;
+}
+
+
diff --git a/doc/ws_main.py b/doc/ws_main.py
new file mode 100755
index 00000000..d1a14050
--- /dev/null
+++ b/doc/ws_main.py
@@ -0,0 +1,1095 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# hhaim, 2014 (IL) base on WAF book
+
+"""
+call 'waf --targets=waf.pdf' or use 'waf list' to see the targets available
+"""
+
+VERSION='0.0.1'
+APPNAME='wafdocs'
+
+import os, re, shutil
+import sys
+import shlex
+import subprocess
+import json
+import re
+from waflib import Logs
+
+
+top = '.'
+out = 'build'
+sphinx_version = None
+
+try:
+ from HTMLParser import HTMLParser
+except:
+ from html.parser import HTMLParser
+
+class CTocNode:
+ def __init__ (self):
+ self.name="root"
+ self.level=1; # 1,2,3,4
+ self.link=None;
+ self.parent=None
+ self.childs=[]; # link to CTocNode
+
+ def get_link (self):
+ if self.link==None:
+ name=self.name
+ l=name.split('.');
+ l=l[-1].lower()
+ s='';
+ for c in l:
+ if c.isalpha() or c.isspace():
+ s+=c
+
+ return '#_'+'_'.join(s.lower().split());
+ else:
+ return '#'+self.link
+
+
+
+ def add_new_child (self,name,level,link):
+ n=CTocNode();
+ n.name=name;
+ n.link=link
+ n.level=level;
+ n.parent=self;
+ self.childs.append(n);
+ return n
+
+ def to_json_childs (self):
+ l=[]
+ for obj in self.childs:
+ l.append(obj.to_json());
+ return (l);
+
+ def to_open (self):
+ if self.level <3:
+ return True
+ else:
+ return False
+
+
+ def to_json (self):
+ d={"text" : self.name,
+ "link" : self.get_link(),
+ "state" : {
+ "opened" : self.to_open()
+ }
+ }
+ if len(self.childs)>0 :
+ d["children"]= self.to_json_childs()
+ return d
+
+
+
+class TocHTMLParser(HTMLParser):
+
+ def __init__ (self):
+ HTMLParser.__init__(self);
+ self.state=0;
+ self.root=CTocNode()
+ self.root.parent=self.root
+ self.level=2;
+ self.attrs=None
+ self.d={};
+ self.last_level=1
+ self.set_level(1,self.root)
+
+
+ def set_level (self,level,node):
+ assert(node!=None);
+ assert(isinstance(node,CTocNode)==True);
+ self.d[str(level)]=node
+
+ # in case we change from high to low level remove the higher level
+ if level<self.last_level:
+ for l in range(level+1,self.last_level+1):
+ self.d.pop(str(l),None)
+
+
+
+ def _get_level (self,level):
+ k=str(level)
+ if k in self.d:
+ n=self.d[k]
+ assert(n!=None);
+ return n
+ else:
+ return None
+
+ def get_level (self,level):
+ for l in range(level,0,-1):
+ n=self._get_level(l)
+ if n != None:
+ return n
+ assert(0);
+
+
+ def is_header (self,tag):
+ if len(tag)==2 and tag[0]=='h' and tag[1].isdigit() and (int(tag[1])>1):
+ return (True);
+
+ def handle_starttag(self, tag, attrs):
+ if self.is_header (tag):
+ self.attrs=attrs
+ self.state=True;
+ self.level=int(tag[1]);
+
+ def handle_endtag(self, tag):
+ if self.is_header (tag):
+ self.state=False;
+
+ def get_id (self):
+ if self.attrs:
+ for obj in self.attrs:
+ if obj[0]=='id':
+ return obj[1]
+ else:
+ return None
+
+
+ def handle_data(self, data):
+ if self.state:
+
+ level=self.level
+
+ cnode=self.get_level(level-1)
+
+ n=cnode.add_new_child(data,level,self.get_id());
+ assert(n!=None);
+ self.set_level(level,n)
+ self.last_level=level
+
+ def dump_as_json (self):
+ return json.dumps(self.root.to_json_childs(), sort_keys=False, indent=4)
+
+
+
+
+def create_toc_json (input_file,output_file):
+ f = open (input_file)
+ l=f.readlines()
+ f.close();
+ html_input = ''.join(l)
+ parser = TocHTMLParser()
+ parser.feed(html_input);
+ f = open (output_file,'w')
+ f.write(parser.dump_as_json());
+ f.close();
+
+
+
+
+re_xi = re.compile('''^(include|image)::([^.]*.(asciidoc|\\{PIC\\}))\[''', re.M)
+def ascii_doc_scan(self):
+ p = self.inputs[0].parent
+ node_lst = [self.inputs[0]]
+ seen = []
+ depnodes = []
+ while node_lst:
+ nd = node_lst.pop(0)
+ if nd in seen: continue
+ seen.append(nd)
+
+ code = nd.read()
+ for m in re_xi.finditer(code):
+ name = m.group(2)
+ if m.group(3) == '{PIC}':
+
+ ext = '.eps'
+ if self.generator.rule.rfind('A2X') > 0:
+ ext = '.png'
+
+ k = p.find_resource(name.replace('{PIC}', ext))
+ if k:
+ depnodes.append(k)
+ else:
+ k = p.find_resource(name)
+ if k:
+ depnodes.append(k)
+ node_lst.append(k)
+ return [depnodes, ()]
+
+
+
+def scansize(self):
+ name = 'image::%s\\{PIC\\}\\[.*,(width|height)=(\\d+)' % self.inputs[0].name[:-4]
+ re_src = re.compile(name)
+ lst = self.inputs[0].parent.get_src().ant_glob('*.txt')
+ for x in lst:
+ m = re_src.search(x.read())
+ if m:
+ val = str(int(1.6 * int(m.group(2))))
+ if m.group(1) == 'width':
+ w = val
+ h = "800"
+ else:
+ w = "800"
+ h = val
+
+ ext = self.inputs[0].name[-3:]
+ if ext == 'eps':
+ code = '-geometry %sx%s' % (w, h)
+ elif ext == 'dia':
+ if m.group(1) == 'width':
+ h = ''
+ else:
+ w = ''
+ code = '--size %sx%s' % (w, h)
+ else:
+ code = '-Gsize="%s,%s"' % (w, h)
+ break
+ else:
+ return ([], '')
+
+ return ([], code)
+
+def options(opt):
+ opt.add_option('--exe', action='store_true', default=False, help='Execute the program after it is compiled')
+
+def configure(conf):
+ search_path = '~/.local/bin /usr/local/bin/ /usr/bin'
+ conf.find_program('asciidoc', path_list=search_path, var='ASCIIDOC')
+ conf.find_program('sphinx-build', path_list=search_path, var='SPHINX')
+ conf.find_program('source-highlight', path_list=search_path, var='SRC_HIGHLIGHT')
+ conf.find_program('dblatex', path_list=search_path, var='DBLATEX')
+ conf.find_program('a2x', path_list=search_path, var='A2X')
+ pass;
+
+def convert_to_pdf(task):
+ input_file = task.outputs[0].abspath()
+ out_dir = task.outputs[0].parent.get_bld().abspath()
+ return os.system('a2x --no-xmllint %s -f pdf -d article %s -D %s ' %('-v' if Log.verbose else '', task.inputs[0].abspath(),out_dir ) )
+
+
+TOC_HEAD = """
+
+<body class="book">
+<div id="toc-section">
+ <div id="toctitle">
+ <img class="trex_logo" src="images/trex_logo_toc.png"/>
+ Table of Contents
+ </div>
+
+ <div id="toggle">
+ <img src="images/icons/toggle.png" title="click to toggle table of contents"/>
+ </div>
+
+ <div id="toc">
+ <div id="nav-tree">
+
+ </div>
+ </div>
+</div>
+
+<div id="content-section">
+
+ <!-- load the theme CSS file -->
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" rel="stylesheet"/>
+
+ <link href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" rel="stylesheet" />
+
+ <!-- include the jQuery library -->
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js">
+ </script>
+
+ <!-- include the jQuery UI library -->
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js">
+ </script>
+
+ <!-- include the minified jstree source -->
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js">
+ </script>
+
+ <!-- Hide TOC on mobile -->
+ <script>
+
+ // Hide TOC when it is mobile
+ checkMobile();
+
+ // Hide TOC by default if it is mobile
+ function checkMobile(){
+ if(isMobileDevice()){
+ hideTOC();
+ }
+ }
+
+ // Check it it it is running on mobile device
+ function isMobileDevice() {
+ if(
+ navigator.userAgent.match(/Android/i) ||
+ navigator.userAgent.match(/BlackBerry/i) ||
+ navigator.userAgent.match(/iPhone|iPad|iPod/i) ||
+ navigator.userAgent.match(/Opera Mini/i) ||
+ navigator.userAgent.match(/IEMobile/i) ||
+ navigator.userAgent.match(/iPhone|iPad|iPod/i)
+ )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Hide TOC - for the first time in mobile
+ function hideTOC(){
+ $("#toc").hide();
+ $("#toctitle").hide();
+ // Show the show/hide button
+ $("#toggle").css("right", "-40px");
+ // Fil width
+ $("body").css("margin-left", "50px");
+ }
+
+ </script>
+
+ <div id="content-section-inner">
+
+"""
+
+TOC_END = """
+
+ </div>
+ <!-- End Of Inner Content Section -->
+</div>
+<!-- End of Content Section -->
+
+</body>
+
+<style type="text/css">
+ #toc {
+ margin-bottom: 2.5em;
+ }
+
+ #toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+ }
+
+ @media screen {
+ body {
+ margin-left: 20em;
+ }
+
+ #toc {
+ position: fixed;
+ top: 51px;
+ left: 0;
+ bottom: 0;
+ width: 18em;
+ padding-bottom: 1.5em;
+ margin: 0;
+ overflow-x: auto !important;
+ overflow-y: auto !important;
+ border-right: solid 2px #cfcfcf;
+ background-color: #FAFAFA;
+ white-space: nowrap;
+ }
+
+ #toctitle {
+ font-size: 17px !important;
+ color: #4d4d4d !important;
+ margin-top: 0px;
+ height: 36px;
+ line-height: 36px;
+ background-color: #e4e2e2;
+ padding: 8px 0px 7px 45px;
+ white-space: nowrap;
+ left: 0px;
+ display: block;
+ position: fixed;
+ z-index: 100;
+ width: 245px;
+ top: 0px;
+ overflow: hidden;
+ }
+
+ #toc .toclevel1 {
+ margin-top: 0.5em;
+ }
+
+ #toc .toclevel2 {
+ margin-top: 0.25em;
+ display: list-item;
+ color: #aaaaaa;
+ }
+
+ }
+
+
+ /* Custom for Nave Tree */
+ #nav-tree{
+ margin-left: 10px !important;
+ }
+
+ #nav-tree ul > li {
+ color: #000 !important;
+ }
+
+ .jstree-wholerow.jstree-wholerow-clicked {
+ background-image: url('images/icons/selected_tab_bg.png');
+ background-repeat: repeat-x;
+ color: #fff !important;
+ text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
+ }
+
+ /* For side bar */
+ .ui-resizable-e{
+ height: 100%;
+ width: 4px !important;
+ position: fixed !important;
+ top: 0px !important;
+ cursor: e-resize !important;
+ background: url('images/splitbar.png') repeat scroll right center transparent !important;
+ }
+
+ .jstree-default .jstree-themeicon{
+ display: none !important;
+ }
+
+
+ .jstree-anchor {
+ font-size: 12px !important;
+ color: #91A501 !important;
+ }
+
+
+ .jstree-clicked{
+ color: white !important;
+ }
+
+
+ #toggle {
+ position: fixed;
+ top: 14px;
+ left: 10px;
+ z-index: 210;
+ width: 24px;
+ }
+
+ #toggle img {
+ opacity:0.3;
+ }
+
+ #toggle img:hover {
+ opacity:0.9;
+ }
+
+ .trex_logo{
+ top: 6px;
+ position: relative;
+ }
+
+ html{
+ overflow: hidden;
+ }
+
+ body{
+ margin-right: 0px !important;
+ margin-top: 0px !important;
+ margin-bottom: 0px !important;
+ }
+
+ #toc-section{
+ position: absolute;
+ z-index: 200;
+ }
+
+ #content-section{
+ overflow: auto;
+ }
+
+ #content-section-inner{
+ max-width: 50em;
+ }
+
+
+ </style>
+
+
+
+<script>
+
+ $(document).ready(function(){
+ var isOpen = true;
+
+ // Initialize NavTree
+ initializeNavTree();
+ // Drag TOC left and right
+ initResizable();
+ // Toggle TOC whe clicking on the menu icon
+ toggleTOC();
+ // Handle Mobile - close TOC
+ checkMobile();
+
+ function initializeNavTree() {
+
+ // TOC tree options
+ var toc_tree = $('#nav-tree');
+
+ var toc_tree_options = {
+ 'core' : {
+ "animation" :false,
+ "themes" : { "stripes" : false },
+ 'data' : {
+ "url" : "./input_replace_me.json",
+ "dataType" : "json" // needed only if you do not supply JSON headers
+ }
+ }
+ ,
+ "plugins" : [ "wholerow" ]
+ };
+
+ $('#nav-tree').jstree(toc_tree_options) ;
+
+ toc_tree.on("changed.jstree", function (e, data) {
+ window.location.href = data.instance.get_selected(true)[0].original.link;
+ });
+ }
+
+ function initResizable() {
+ var toc = $("#toc");
+ var body = $("body");
+
+ // On resize
+ $("#toc").resizable({
+ resize: function(e, ui) {
+ resized();
+ },
+ handles: 'e'
+ });
+
+ // On zoom changed
+ $(window).resize(function() {
+ if(isOpen){
+ resized();
+ }
+ });
+
+
+ // Do it for the first time
+ var tocWidth = $(toc).outerWidth();
+ var windowHeight = $(window).height();
+ $(".ui-resizable-e").css({"right":$(window).width()-parseInt(tocWidth)+"px"});
+ $("#toctitle").css({"width":parseInt(tocWidth)-45+"px"});
+ $("#toc-section").css({"height":windowHeight + "px"});
+ $("#content-section").css({"height":windowHeight + "px"});
+
+ }
+
+ function resized(){
+ var body = $("body");
+ var tocWidth = $(toc).outerWidth();
+ var windowHeight = $(window).height();
+
+ body.css({"marginLeft":parseInt(tocWidth)+20+"px"});
+ $(".ui-resizable-e").css({"right":$(window).width()-parseInt(tocWidth)+"px"});
+ $("#toctitle").css({"width":parseInt(tocWidth)-45+"px"});
+ $("#toc-section").css({"height":windowHeight + "px"});
+ $("#content-section").css({"height":windowHeight + "px"});
+
+ }
+
+
+ function toggleTOC(){
+ $( "#toggle" ).click(function() {
+ if ( isOpen ) {
+ // Close it
+ closTOC();
+ } else {
+ // Open it
+ openTOC();
+ }
+ // Toggle status
+ isOpen = !isOpen;
+ });
+ }
+
+
+ // Close TOC by default if it is mobile
+ function checkMobile(){
+ if(isMobileDevice()){
+ isOpen=false;
+ $(".ui-resizable-e").hide();
+ }
+ }
+
+ // Check it it it is running on mobile device
+ function isMobileDevice() {
+ if(
+ navigator.userAgent.match(/Android/i) ||
+ navigator.userAgent.match(/BlackBerry/i) ||
+ navigator.userAgent.match(/iPhone|iPad|iPod/i) ||
+ navigator.userAgent.match(/Opera Mini/i) ||
+ navigator.userAgent.match(/IEMobile/i) ||
+ navigator.userAgent.match(/iPhone|iPad|iPod/i)
+ )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Close TOC
+ function closTOC(){
+ $("#toc").hide("slide", 500);
+ $("#toctitle").hide("slide", 500);
+ if(!isMobileDevice()){
+ $(".ui-resizable-e").hide("slide", 500);
+ }
+ // Show the show/hide button
+ $("#toggle").css("right", "-40px");
+ // Fil width
+ $("body").animate({"margin-left": "50px"}, 500);
+ }
+
+ // Open TOC
+ function openTOC(){
+ $("#toc").show("slide", 500);
+ $("#toctitle").show("slide", 500);
+ if(!isMobileDevice()){
+ $(".ui-resizable-e").show("slide", 500);
+ }
+ // Show the show/hide button
+ $("#toggle").css("right", "15px");
+ // Minimize page width
+ $("body").animate({"margin-left": $(toc).outerWidth()+20+"px"}, 500);
+ }
+
+ });
+
+</script>
+
+"""
+
+def do_replace (input_file,contents,look,str_replaced):
+ if contents.count(look)!=1 :
+ raise Exception('Cannot find {0} in file {1} '.format(look,input_file))
+
+ return contents.replace(look, str_replaced)
+
+
+
+def toc_fixup_file (input_file,
+ out_file,
+ json_file_name
+ ):
+
+ file = open(input_file)
+ contents = file.read()
+
+ contents = do_replace(input_file,contents,'<body class="book">', TOC_HEAD);
+ contents = do_replace(input_file,contents,'</body>', TOC_END)
+ contents = do_replace(input_file,contents,'input_replace_me.json', json_file_name)
+
+ file = open(out_file,'w')
+ file.write(contents)
+ file.close();
+
+
+
+def convert_to_html_toc_book(task):
+
+ input_file = task.inputs[0].abspath()
+
+ json_out_file = os.path.splitext(task.outputs[0].abspath())[0]+'.json'
+ tmp = os.path.splitext(task.outputs[0].abspath())[0]+'.tmp'
+ json_out_file_short = os.path.splitext(task.outputs[0].name)[0]+'.json'
+
+ cmd='{0} -a stylesheet={1} -a icons=true -a docinfo -d book -o {2} {3}'.format(
+ task.env['ASCIIDOC'][0],
+ task.inputs[1].abspath(),
+ tmp,
+ task.inputs[0].abspath());
+
+ res= os.system( cmd )
+ if res !=0 :
+ return (1)
+
+ create_toc_json(tmp,json_out_file)
+
+ toc_fixup_file(tmp,task.outputs[0].abspath(),json_out_file_short);
+
+ return os.system('rm {0}'.format(tmp));
+
+
+
+
+def convert_to_pdf_book(task):
+ input_file = task.outputs[0].abspath()
+ out_dir = task.outputs[0].parent.get_bld().abspath()
+ return os.system('a2x --no-xmllint %s -f pdf -d book %s -D %s ' %('-v' if Logs.verbose else '', task.inputs[0].abspath(),out_dir ) )
+
+
+def ensure_dir(f):
+ if not os.path.exists(f):
+ os.makedirs(f)
+
+
+def my_copy(task):
+ input_file=task.outputs[0].abspath()
+ out_dir=task.outputs[0].parent.get_bld().abspath()
+ ensure_dir(out_dir)
+ shutil.copy2(input_file, out_dir+ os.sep+task.outputs[0].name)
+ return (0)
+
+
+def do_visio(bld):
+ for x in bld.path.ant_glob('visio\\*.vsd'):
+ tg = bld(rule='${VIS} -i ${SRC} -o ${TGT} ', source=x, target=x.change_ext('.png'))
+
+def get_sphinx_version(sphinx_path):
+ try:
+ global sphinx_version
+ if not sphinx_version:
+ sphinx_version_regexp = '^Sphinx \(sphinx-build\) (\d+)\.(\d+)\.\d+$'
+ cmd = '%s %s --version' % (sys.executable, sphinx_path)
+ output = subprocess.check_output(shlex.split(cmd), universal_newlines = True)
+ for line in output.splitlines():
+ ver = re.match(sphinx_version_regexp, line)
+ if ver:
+ sphinx_version = float('%s.%s' % (ver.group(1), ver.group(2)))
+ return sphinx_version
+ except Exception as e:
+ print('Error getting Sphinx version: %s' % e)
+
+def get_trex_core_git():
+ trex_core_git_path = os.path.join(os.getcwd(), os.pardir, "trex-core")
+ if not os.path.isdir(trex_core_git_path):
+ trex_core_git_path = os.getenv('TREX_CORE_GIT', None)
+ return trex_core_git_path
+
+def parse_hlt_args(task):
+ trex_core_git_path = get_trex_core_git()
+ if not trex_core_git_path:
+ return 1
+ hltapi_path = os.path.abspath(os.path.join(trex_core_git_path, 'scripts', 'automation', 'trex_control_plane', 'stl', 'trex_stl_lib', 'trex_stl_hltapi.py'))
+ header = ['[options="header",cols="<.^1,^.^1,9<.^e"]', '|=================', '^| Argument | Default ^| Comment']
+ footer = ['|=================\n']
+ hlt_asciidoc = []
+ category_regexp = '^(\S+)_kwargs = {$'
+ comment_line_regexp = '^\s*#\s*(.+)$'
+ arg_line_regexp = "^\s*'([^']+)':\s*'?([^,']+)'?,\s*#?\s*(.+)?$"
+ if not os.path.exists(hltapi_path):
+ raise Exception('Could not find hltapi file: %s' % hltapi_path)
+ with open(hltapi_path) as f:
+ in_args = False
+ for line in f.read().splitlines():
+ if not in_args:
+ if line.startswith('import'):
+ break
+ category_line = re.match(category_regexp, line)
+ if category_line:
+ hlt_asciidoc.append('\n===== %s\n' % category_line.group(1))
+ hlt_asciidoc += header
+ in_args = True
+ continue
+ comment_line = re.match(comment_line_regexp, line)
+ if comment_line:
+ hlt_asciidoc.append('3+^.^s| %s' % comment_line.group(1).replace('|', '\|'))
+ continue
+ arg_line = re.match(arg_line_regexp, line)
+ if arg_line:
+ arg, default, comment = arg_line.groups()
+ hlt_asciidoc.append('| %s | %s | %s' % (arg, default, comment.replace('|', '\|') if comment else ''))
+ continue
+ if line == '}':
+ hlt_asciidoc += footer
+ in_args = False
+ if not len(hlt_asciidoc):
+ raise Exception('Parsing of hltapi args failed')
+ with open('build/hlt_args.asciidoc', 'w') as f:
+ f.write('\n'.join(hlt_asciidoc))
+ return 0
+
+def build_cp_docs (task):
+ out_dir = task.outputs[0].abspath()
+ export_path = os.path.join(os.getcwd(), 'build', 'cp_docs')
+ trex_core_git_path = get_trex_core_git()
+ if not trex_core_git_path: # there exists a default directory or the desired ENV variable.
+ return 1
+ trex_core_docs_path = os.path.abspath(os.path.join(trex_core_git_path, 'scripts', 'automation', 'trex_control_plane', 'doc'))
+ sphinx_version = get_sphinx_version(task.env['SPHINX'][0])
+ if not sphinx_version:
+ return 1
+ if sphinx_version < 1.3:
+ additional_args = '-D html_theme=default'
+ else:
+ additional_args = ''
+ build_doc_cmd = "{pyt} {sph} {add} {ver} -W -b {bld} {src} {dst}".format(
+ pyt= sys.executable,
+ sph= task.env['SPHINX'][0],
+ add= additional_args,
+ ver= '' if Logs.verbose else '-q',
+ bld= "html",
+ src= ".",
+ dst= out_dir)
+ if Logs.verbose:
+ print(build_doc_cmd)
+ try:
+ return subprocess.call(shlex.split(build_doc_cmd), cwd = trex_core_docs_path)
+ except OSError as e:
+ print('Failed command: %s\nError: %s' % (build_doc_cmd, e))
+ return 1
+
+def build_stl_cp_docs (task):
+ out_dir = task.outputs[0].abspath()
+ export_path = os.path.join(os.getcwd(), 'build', 'cp_stl_docs')
+ trex_core_git_path = get_trex_core_git()
+ if not trex_core_git_path: # there exists a default directory or the desired ENV variable.
+ return 1
+ trex_core_docs_path = os.path.abspath(os.path.join(trex_core_git_path, 'scripts', 'automation', 'trex_control_plane', 'doc_stl'))
+ sphinx_version = get_sphinx_version(task.env['SPHINX'][0])
+ if not sphinx_version:
+ return 1
+ if sphinx_version < 1.3:
+ additional_args = '-D html_theme=default'
+ else:
+ additional_args = ''
+ build_doc_cmd = "{pyt} {sph} {add} {ver} -W -b {bld} {src} {dst}".format(
+ pyt= sys.executable,
+ sph= task.env['SPHINX'][0],
+ add= additional_args,
+ ver= '' if Logs.verbose else '-q',
+ bld= "html",
+ src= ".",
+ dst= out_dir)
+ if Logs.verbose:
+ print(build_doc_cmd)
+ try:
+ return subprocess.call(shlex.split(build_doc_cmd), cwd = trex_core_docs_path)
+ except OSError as e:
+ print('Failed command: %s\nError: %s' % (build_doc_cmd, e))
+ return 1
+
+
+
+def build_cp(bld,dir,root,callback):
+ export_path = os.path.join(os.getcwd(), 'build', dir)
+ trex_core_git_path = get_trex_core_git()
+ if not trex_core_git_path: # there exists a default directory or the desired ENV variable.
+ raise NameError("Environment variable 'TREX_CORE_GIT' is not defined.")
+ trex_core_docs_path = os.path.join(trex_core_git_path, 'scripts', 'automation', 'trex_control_plane', root, 'index.rst')
+ bld(rule=callback,target = dir)
+
+
+
+
+
+
+
+
+
+
+
+def build(bld):
+ bld(rule=my_copy, target='symbols.lang')
+
+ for x in bld.path.ant_glob('images\\**\**.png'):
+ bld(rule=my_copy, target=x)
+ bld.add_group()
+
+
+ for x in bld.path.ant_glob('yaml\\**\**.yaml'):
+ bld(rule=my_copy, target=x)
+ bld.add_group()
+
+
+ for x in bld.path.ant_glob('video\\**\**.mp4'):
+ bld(rule=my_copy, target=x)
+ bld.add_group()
+
+
+ for x in bld.path.ant_glob('images\\**\**.jpg'):
+ bld(rule=my_copy, target=x)
+ bld.add_group()
+
+ bld(rule=my_copy, target='my_chart.js')
+
+ build_cp(bld,'hlt_args.asciidoc','stl/trex_stl_lib', parse_hlt_args)
+
+ bld.add_group() # separator, the documents may require any of the pictures from above
+
+ if os.path.exists('build/hlt_args.asciidoc'):
+ bld.add_manual_dependency(
+ bld.path.find_node('trex_stateless.asciidoc'),
+ b'build/hlt_args.asciidoc')
+
+ bld(rule='${ASCIIDOC} -f ../backends/deckjs/deckjs.conf -o ${TGT} ${SRC[0].abspath()}',
+ source='trex_config.asciidoc ', target='trex_config_guide.html', scan=ascii_doc_scan)
+
+
+ bld(rule='${ASCIIDOC} -f ../backends/deckjs/deckjs.conf -o ${TGT} ${SRC[0].abspath()}',
+ source='trex_preso.asciidoc ', target='trex_preso.html', scan=ascii_doc_scan)
+
+ bld(rule='${ASCIIDOC} -a stylesheet=${SRC[1].abspath()} -a icons=true -a max-width=55em -o ${TGT} ${SRC[0].abspath()}',
+ source='release_notes.asciidoc waf.css', target='release_notes.html', scan=ascii_doc_scan)
+
+ bld(rule='${ASCIIDOC} -a docinfo -a stylesheet=${SRC[1].abspath()} -a icons=true -a toc2 -a max-width=55em -d book -o ${TGT} ${SRC[0].abspath()}',
+ source='draft_trex_stateless.asciidoc waf.css', target='draft_trex_stateless.html', scan=ascii_doc_scan)
+
+ bld(rule='${ASCIIDOC} -a docinfo -a stylesheet=${SRC[1].abspath()} -a icons=true -a toc2 -a max-width=55em -d book -o ${TGT} ${SRC[0].abspath()}',
+ source='draft_trex_stateless_moved1.asciidoc waf.css', target='draft_trex_stateless1.html', scan=ascii_doc_scan)
+
+ bld(rule=convert_to_pdf_book,source='trex_book.asciidoc waf.css', target='trex_book.pdf', scan=ascii_doc_scan)
+
+ bld(rule=convert_to_pdf_book,source='trex_stateless.asciidoc waf.css', target='trex_stateless.pdf', scan=ascii_doc_scan)
+
+ bld(rule=convert_to_pdf_book,source='draft_trex_stateless.asciidoc waf.css', target='draft_trex_stateless.pdf', scan=ascii_doc_scan)
+
+ bld(rule=convert_to_pdf_book,source='trex_vm_manual.asciidoc waf.css', target='trex_vm_manual.pdf', scan=ascii_doc_scan)
+
+ bld(rule=convert_to_pdf_book,source='trex_control_plane_peek.asciidoc waf.css', target='trex_control_plane_peek.pdf', scan=ascii_doc_scan)
+
+ bld(rule=convert_to_pdf_book, source='trex_control_plane_design_phase1.asciidoc waf.css', target='trex_control_plane_design_phase1.pdf', scan=ascii_doc_scan)
+
+ # with nice TOC
+ bld(rule=convert_to_html_toc_book,
+ source='trex_vm_manual.asciidoc waf.css', target='trex_vm_manual.html',scan=ascii_doc_scan)
+
+ bld(rule=convert_to_html_toc_book,
+ source='trex_stateless.asciidoc waf.css', target='trex_stateless.html',scan=ascii_doc_scan);
+
+ bld(rule=convert_to_html_toc_book,
+ source='trex_stateless_bench.asciidoc waf.css', target='trex_stateless_bench.html',scan=ascii_doc_scan);
+
+ bld(rule=convert_to_html_toc_book,
+ source='trex_book.asciidoc waf.css', target='trex_manual.html',scan=ascii_doc_scan);
+
+ bld(rule=convert_to_html_toc_book,
+ source='trex_faq.asciidoc waf.css', target='trex_faq.html',scan=ascii_doc_scan);
+
+ bld(rule=convert_to_html_toc_book,
+ source='trex_rpc_server_spec.asciidoc waf.css', target='trex_rpc_server_spec.html',scan=ascii_doc_scan);
+
+ bld(rule=convert_to_html_toc_book,
+ source='trex_scapy_rpc_server.asciidoc waf.css', target='trex_scapy_rpc_server.html',scan=ascii_doc_scan);
+
+ bld(rule='${ASCIIDOC} -a stylesheet=${SRC[1].abspath()} -a icons=true -a toc2 -a max-width=55em -o ${TGT} ${SRC[0].abspath()}',
+ source='vm_doc.asciidoc waf.css', target='vm_doc.html', scan=ascii_doc_scan)
+
+ bld(rule='${ASCIIDOC} -a stylesheet=${SRC[1].abspath()} -a icons=true -a toc2 -a max-width=55em -o ${TGT} ${SRC[0].abspath()}',
+ source='packet_builder_yaml.asciidoc waf.css', target='packet_builder_yaml.html', scan=ascii_doc_scan)
+
+
+ bld(rule='${ASCIIDOC} -a stylesheet=${SRC[1].abspath()} -a icons=true -a toc2 -a max-width=55em -o ${TGT} ${SRC[0].abspath()}',
+ source='trex_control_plane_design_phase1.asciidoc waf.css', target='trex_control_plane_design_phase1.html', scan=ascii_doc_scan)
+
+ bld(rule='${ASCIIDOC} -a stylesheet=${SRC[1].abspath()} -a icons=true -a toc2 -a max-width=55em -o ${TGT} ${SRC[0].abspath()}',
+ source='trex_control_plane_peek.asciidoc waf.css', target='trex_control_plane_peek.html', scan=ascii_doc_scan)
+
+ bld(rule='${ASCIIDOC} -a stylesheet=${SRC[1].abspath()} -a icons=true -a toc2 -a max-width=55em -o ${TGT} ${SRC[0].abspath()}',
+ source='trex_console.asciidoc waf.css', target='trex_console.html', scan=ascii_doc_scan)
+
+ bld(rule='${ASCIIDOC} -a stylesheet=${SRC[1].abspath()} -a icons=true -a max-width=55em -o ${TGT} ${SRC[0].abspath()}',
+ source='trex_index.asciidoc waf.css', target='index.html', scan=ascii_doc_scan)
+
+ build_cp(bld,'cp_docs','doc',build_cp_docs)
+
+ build_cp(bld,'cp_stl_docs','doc_stl',build_stl_cp_docs)
+
+
+class Env(object):
+ @staticmethod
+ def get_env(name) :
+ s= os.environ.get(name);
+ if s == None:
+ print("You should define $",name)
+ raise Exception("Env error");
+ return (s);
+
+ @staticmethod
+ def get_release_path () :
+ s= Env().get_env('TREX_LOCAL_PUBLISH_PATH');
+ s +=get_build_num ()+"/"
+ return s;
+
+ @staticmethod
+ def get_remote_release_path () :
+ s= Env().get_env('TREX_REMOTE_PUBLISH_PATH');
+ return s;
+
+ @staticmethod
+ def get_local_web_server () :
+ s= Env().get_env('TREX_WEB_SERVER');
+ return s;
+
+ # extral web
+ @staticmethod
+ def get_trex_ex_web_key() :
+ s= Env().get_env('TREX_EX_WEB_KEY');
+ return s;
+
+ @staticmethod
+ def get_trex_ex_web_path() :
+ s= Env().get_env('TREX_EX_WEB_PATH');
+ return s;
+
+ @staticmethod
+ def get_trex_ex_web_user() :
+ s= Env().get_env('TREX_EX_WEB_USER');
+ return s;
+
+ @staticmethod
+ def get_trex_ex_web_srv() :
+ s= Env().get_env('TREX_EX_WEB_SRV');
+ return s;
+
+ @staticmethod
+ def get_trex_core() :
+ s= Env().get_env('TREX_CORE_GIT');
+ return s;
+
+
+
+def release(bld):
+ # copy all the files to our web server
+ core_dir = Env().get_trex_core()
+ release_dir = core_dir +"/scripts/doc/";
+ os.system('mkdir -p '+release_dir)
+ os.system('cp -rv build/release_notes.* '+ release_dir)
+
+
+def publish(bld):
+ # copy all the files to our web server
+ remote_dir = "%s:%s" % ( Env().get_local_web_server(), Env().get_remote_release_path ()+'../doc/')
+ os.system('rsync -av --del --rsh=ssh build/ %s' % (remote_dir))
+
+
+def publish_ext(bld):
+ from_ = 'build/'
+ os.system('rsync -avz --del -e "ssh -i %s" --rsync-path=/usr/bin/rsync %s %s@%s:%s/doc/' % (Env().get_trex_ex_web_key(),from_, Env().get_trex_ex_web_user(),Env().get_trex_ex_web_srv(),Env().get_trex_ex_web_path() ) )
+
+
+def publish_test(bld):
+ # copy all the files to our web server
+ remote_dir = "%s:%s" % ( Env().get_local_web_server(), Env().get_remote_release_path ()+'../test/')
+ os.system('rsync -av --del --rsh=ssh build/ %s' % (remote_dir))
+
+
+
+def publish_both(bld):
+ publish(bld)
+ publish_ext(bld)
+
+
+def test(bld):
+ # copy all the files to our web server
+ toc_fixup_file ('build/trex_stateless.tmp',
+ 'build/trex_stateless.html',
+ 'trex_stateless.json')
+
+
+
diff --git a/doc/wscript b/doc/wscript
new file mode 100755
index 00000000..187a5528
--- /dev/null
+++ b/doc/wscript
@@ -0,0 +1,68 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# hhaim, 2014 (IL) base on WAF book
+
+"""
+call 'waf --targets=waf.pdf' or use 'waf list' to see the targets available
+"""
+
+VERSION='0.0.1'
+APPNAME='wafdocs'
+
+import ws_main
+
+
+top = '.'
+out = 'build'
+
+
+def options(opt):
+ ws_main.options(opt)
+
+
+def configure(conf):
+ ws_main.configure(conf)
+
+
+def create_toc (bld):
+ ws_main.create_toc(bld)
+
+def build(bld):
+ ws_main.build(bld)
+
+
+def build_info(bld):
+ ws_main.build_info(bld)
+
+def pkg(bld):
+ ws_main.pkg(bld)
+
+def release(bld):
+ ws_main.release(bld)
+
+def publish(bld):
+ ws_main.publish(bld)
+
+def publish_test(bld):
+ ws_main.publish_test(bld)
+
+def publish_ext(bld):
+ ws_main.publish_ext(bld)
+
+def publish_web(bld):
+ ws_main.publish_web(bld)
+
+def sync(bld):
+ ws_main.sync(bld)
+
+def test(bld):
+ ws_main.test(bld)
+
+def show(bld):
+ ws_main.show(bld)
+
+def publish_both(bld):
+ ws_main.publish_both(bld)
+
+
+
diff --git a/doc/yaml/headers.yaml b/doc/yaml/headers.yaml
new file mode 100755
index 00000000..14a94e56
--- /dev/null
+++ b/doc/yaml/headers.yaml
@@ -0,0 +1,500 @@
+# This yaml describes packet headers and their fields
+
+
+#######################################################################
+# Root, reserved starting point
+
+
+ - class: 'root'
+ gui_representation:
+ help: 'Root'
+ next_headers: ['ethernet', 'llc', '_802-3']
+
+
+#######################################################################
+# Protocols
+
+
+# L2
+
+
+ - class: 'ethernet'
+ gui_representation:
+ help: 'Ethernet-L2'
+ properties: ['external']
+ default: [0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00]
+ fields:
+ - name: 'Dst'
+ gui_representation:
+ help: 'Destination MAC'
+ type: 'c-mac-addr'
+ default: [0x77, 0x55, 0x01, 0x00, 0x00, 0x01]
+
+ - name: 'Src'
+ gui_representation:
+ help: 'Source MAC'
+ type: 'c-mac-addr'
+
+ - name: 'Ethertype'
+ gui_representation:
+ help: 'Ethertype'
+ type: 'uint16'
+ default: 0x0800
+ value_based_next_header:
+ 0x0800: 'ipv4'
+ 0x86DD: 'ipv6'
+ # not implemented
+ # 0x0806: 'arp'
+ # 0x8100: 'vlan' # field of 4 bytes added in this case, what to do?
+ # 0x8847: 'mpls unicast' # unicast or multicast? multicast is 0x8848
+ default: 'payload'
+
+
+# L3
+
+
+ - class: 'ipv4'
+ gui_representation:
+ help: 'IPv4'
+ properties: ['external']
+ fields:
+ - name: 'ver'
+ gui_representation:
+ help: 'Version'
+ type: 'c-bit'
+ array_size: 4
+ default: [0, 1, 0, 0]
+ properties: ['const']
+
+ - name: 'ihl'
+ gui_representation:
+ help: 'IHL'
+ type: 'c-bit'
+ array_size: 4
+ default: [0, 1, 0, 1]
+ properties: ['ipv4_ihl']
+
+ - name: 'DSCP'
+ gui_representation:
+ help: 'Differentiated Services Code Point'
+ type: 'c-bit'
+ array_size: 6
+ default: [0, 0, 0, 0, 0, 0]
+
+ - name: 'ECN'
+ gui_representation:
+ help: 'Explicit Congestion Notification'
+ type: 'c-bit'
+ array_size: 2
+ default: [0, 0]
+
+ - name: 'total_len'
+ gui_representation:
+ help: 'Total Length'
+ type: 'uint8'
+ array_size: 2
+ default: [0, 57]
+ properties: ['total_length']
+
+ - name: 'Identification'
+ gui_representation:
+ help: 'Identification'
+ type: 'uint8'
+ array_size: 2
+ default: [0x00, 0x00]
+
+ - name: 'Flags'
+ gui_representation:
+ help: 'IPv4 Flags'
+ type: 'c-bit'
+ array_size: 3
+ default: [0, 0, 0]
+ fields:
+ - name: 'Reserved'
+ gui_representation:
+ help: 'Reserved'
+ type: 'bit'
+ default: 0
+ properties: ['const']
+
+ - name: 'DF'
+ gui_representation:
+ help: "Don't Fragment"
+ type: 'bit'
+ default: 0
+
+ - name: 'MF'
+ gui_representation:
+ help: 'More Fragments'
+ type: 'bit'
+ default: 0
+
+ - name: 'Fragment Offset'
+ gui_representation:
+ help: 'Fragment Offset'
+ type: 'c-bit'
+ array_size: 13
+ default: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+
+ - name: 'TTL'
+ gui_representation:
+ help: 'Time To Live'
+ type: 'uint8'
+ default: 0x80
+
+ - name: 'protocol'
+ type: 'uint8'
+ default: 0x06
+ value_based_next_header: &ipv4_next_header
+ 0x06: 'tcp'
+ 0x11: 'udp'
+ 0x29: 'ipv6'
+ # not implemented
+ # 0x2F: 'gre'
+ default: 'payload'
+ gui_representation:
+ help: 'IPv4 next protocol field'
+ combobox_values:
+ <<: *ipv4_next_header
+ 0x11: 'Next header is UDP' # overrides the description for combo-box
+
+ - name: 'ipv4_chksum'
+ gui_representation:
+ help: 'IPv4 Header Checksum'
+ type: 'uint16'
+ default: [0x0000]
+ properties: ['ipv4_checksum', 'const']
+
+ - name: 'Src'
+ gui_representation:
+ help: 'Source IPv4'
+ type: 'c-ipv4-addr'
+
+ - name: 'Dst'
+ gui_representation:
+ help: 'Destination IPv4'
+ type: 'c-ipv4-addr'
+
+ # not implemented
+ # - name: 'Opts' # presence of this field and it's size should be determined in python/java
+ # help: 'IPv4 options'
+ # type: 'c-ipv4-options'
+
+
+ - class: 'ipv6'
+ gui_representation:
+ help: 'IPv6'
+ properties: ['external']
+ fields:
+ - name: 'ver'
+ gui_representation:
+ help: 'Version'
+ type: 'c-bit'
+ array_size: 4
+ default: [0, 1, 1, 0]
+ properties: ['const']
+
+ - name: 'traff_class/diff_serv'
+ gui_representation:
+ help: 'Traffic Class/Diff Serv'
+ type: 'bit'
+ array_size: 8
+ default: [0, 0, 0, 0, 0, 0, 0, 0]
+
+ - name: 'flow_label'
+ gui_representation:
+ help: 'Flow Label'
+ type: 'bit'
+ array_size: 20
+ default: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
+
+ - name: 'payload_length'
+ gui_representation:
+ help: 'Payload Length'
+ type: 'uint16'
+ default: 40
+
+ - name: 'ipv6_next_header'
+ gui_representation:
+ help: 'IPv6 Next Header field'
+ type: 'uint8'
+ value_based_next_header:
+ 6: 'tcp'
+ 17: 'udp'
+ 41: 'ipv6'
+ default: 'tcp'
+
+ - name: 'hop_limit'
+ gui_representation:
+ help: 'IPv6 hop limit'
+ type: 'uint8'
+ default: 200
+
+ - name: 'Src'
+ gui_representation:
+ help: 'Source IPv6'
+ type: 'c-ipv6-addr'
+
+ - name: 'Dst'
+ gui_representation:
+ help: 'Destination IPv6'
+ type: 'c-ipv6-addr'
+
+
+
+# L4
+
+
+ - class: 'tcp'
+ gui_representation:
+ help: 'TCP'
+ properties: ['external']
+ next_headers: ['ipv6', 'ipv4']
+ fields:
+ - name: 'src_port'
+ gui_representation:
+ help: 'Source Port'
+ type: 'c-port-16bit'
+
+ - name: 'dest_port'
+ gui_representation:
+ help: 'Destination Port'
+ type: 'c-port-16bit'
+
+ - name: 'Seq'
+ gui_representation:
+ help: 'Sequence number'
+ type: uint32
+ default: 0x30000000
+
+ - name: 'Ack'
+ gui_representation:
+ help: 'Acknowledgment number'
+ type: uint32
+ default: 0x30000000
+
+ - name: 'Data offset'
+ gui_representation:
+ help: 'Data offset'
+ type: 'c-bit'
+ array_size: 4
+ default: [0, 1, 0, 1]
+
+ - name: 'Reserved'
+ gui_representation:
+ help: 'TCP Reserved'
+ type: 'bit'
+ array_size: 3
+ default: [0, 0, 0]
+ properties: ['const']
+
+ - name: 'flags' # tree with leaf of bits
+ gui_representation:
+ help: 'TCP flags'
+ type: 'c-bit'
+ array_size: 9
+ default: [0, 0, 0, 0, 0, 0, 0, 0, 0]
+ fields:
+ - name: 'ns'
+ gui_representation:
+ help: 'NS flag'
+ type: 'bit'
+ default: 0
+
+ - name: 'cwr'
+ gui_representation:
+ help: 'CWR flag'
+ type: 'bit'
+ default: 0
+
+ - name: 'ece'
+ gui_representation:
+ help: 'ECE flag'
+ type: 'bit'
+ default: 0
+
+ - name: 'urg'
+ gui_representation:
+ help: 'URG flag'
+ type: 'bit'
+ default: 0
+
+ - name: 'ack'
+ gui_representation:
+ help: 'ACK flag'
+ type: 'bit'
+ default: 0
+
+ - name: 'psh'
+ gui_representation:
+ help: 'PSH flag'
+ type: 'bit'
+ default: 0
+
+ - name: 'rst'
+ gui_representation:
+ help: 'RST flag'
+ type: 'bit'
+ default: 0
+
+ - name: 'syn'
+ gui_representation:
+ help: 'SYN flag'
+ type: 'bit'
+ default: 0
+
+ - name: 'window_size'
+ gui_representation:
+ help: 'Window size'
+ type: uint16
+ default: 0x0080
+
+ - name: 'checksum'
+ gui_representation:
+ help: 'Checksum'
+ type: uint16
+ default: 0x0000
+ properties: ['tcp_checksum']
+
+ - name: 'urgent_pointer'
+ gui_representation:
+ help: 'Urgent pointer'
+ type: uint16
+ default: 0x0000
+
+ # not implemented
+ # - name: 'tcp options'
+ # type: 'c-tcp-options'
+
+
+ - class: 'udp'
+ gui_representation:
+ help: 'UDP'
+ properties: ['external']
+ next_headers: ['ipv6', 'ipv4']
+ fields:
+ - name: 'src_port'
+ gui_representation:
+ help: 'Source Port'
+ type: 'c-port-16bit'
+
+ - name: 'dest_port'
+ gui_representation:
+ help: 'Destination Port'
+ type: 'c-port-16bit'
+
+ - name: 'length'
+ gui_representation:
+ help: 'Length'
+ type: 'uint16'
+ default: 0x0020
+ properties: ['total_length']
+
+ - name: 'checksum'
+ gui_representation:
+ help: 'UDP Checksum'
+ type: uint16
+ default: 0x0000
+ properties: ['udp_checksum']
+
+
+#######################################################################
+# Fields
+
+
+ - class: 'c-mac-addr'
+ type: 'uint8'
+ array_size: 6
+ default: [0x00, 0x00, 0x01, 0x00, 0x00, 0x00]
+ gui_representation:
+ help: 'MAC address'
+ data_type: 'mac-addr_t' # format ([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}
+ form_type: 'combo_with_edit'
+
+
+ - class: 'c-ipv4-addr'
+ type: 'uint8'
+ array_size: 4
+ default: [1, 1, 1, 1]
+ gui_representation:
+ help: 'IPv4 address'
+ data_type: 'ipv4_t'
+ form_type: 'combo_with_edit'
+
+
+ - class: 'c-port-16bit'
+ type: 'uint16'
+ default: 0x1234
+ gui_representation:
+ help: 'ports of TCP/UDP etc.'
+ form_type: 'combo_with_edit'
+
+
+ - class: 'c-bit'
+ type: 'bit'
+ gui_representation:
+ help: 'bit with checkbox representation'
+ form_type: 'checkbox'
+
+
+ - class: 'c-ipv6-addr'
+ type: 'uint16'
+ array_size: 8
+ default: [7, 8, 7, 8, 7, 8, 7, 8]
+ gui_representation:
+ help: 'IPv6 address'
+ data_type: 'ipv6_t'
+ form_type: 'combo_with_edit'
+
+
+######################
+# incomplete
+
+ - class: 'c-ipv4-option'
+ type: 'vlen_t'
+ default: 0x01
+ fields:
+ - name: 'copied flag'
+ help: 'Copy the option to all fragments flag'
+ type: 'c-bit'
+ default: 0
+
+ - name: 'option class'
+ help: '0 = controls, 2 = debugging'
+ type: 'bit'
+ array_size: 2
+ default: 0
+
+ - name: 'option number'
+ help: 'Option Number'
+ type: 'bit'
+ array_size: 5
+ value_based_next_class:
+ 0: 'end' # reserved name for ending options
+ 1: 'ip_option' # back to itself
+ 2: 'c-ipv4opt-security'
+ 3: 'c-ipv4opt-loose-source-routing'
+ 4: 'c-ipv4opt-internet-timestamp'
+ 7: 'c-ipv4opt-record-route'
+ 8: 'c-ipv4opt-stream-id'
+ 9: 'c-ipv4opt-strict-source-routing'
+ default: 'end'
+
+
+ - class: 'c-ipv4opt-security'
+ help: 'ipv4 option security'
+ type: 'bit'
+ array_size: 11
+ default: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+ fields:
+ value_based_next_class:
+ default: 'c-ipv4-option'
+
+ - class: 'c-ipv4opt-loose-source-routing'
+ help: 'ipv4 option loose source routing'
+ type: 'bit'
+ default: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+ fields:
+ value_based_next_class:
+ default: 'c-ipv4-option'
+