From 590481ab47520f9bfdfda34630408a09a770f5a1 Mon Sep 17 00:00:00 2001 From: Alina Quereilhac Date: Thu, 26 Mar 2015 19:49:13 +0100 Subject: [PATCH 1/1] add sphinx documentation --- doc/sphinx/Makefile | 153 + .../_build/doctrees/_layout/modules.doctree | Bin 0 -> 2721 bytes .../_build/doctrees/_layout/nepi.data.doctree | Bin 0 -> 3588 bytes .../_layout/nepi.data.processing.ccn.doctree | Bin 0 -> 23918 bytes .../_layout/nepi.data.processing.doctree | Bin 0 -> 3739 bytes .../_layout/nepi.data.processing.ping.doctree | Bin 0 -> 10408 bytes .../_build/doctrees/_layout/nepi.doctree | Bin 0 -> 3634 bytes .../doctrees/_layout/nepi.execution.doctree | Bin 0 -> 620283 bytes .../_layout/nepi.resources.all.doctree | Bin 0 -> 16477 bytes .../doctrees/_layout/nepi.resources.doctree | Bin 0 -> 3838 bytes .../_layout/nepi.resources.linux.ccn.doctree | Bin 0 -> 99708 bytes .../_layout/nepi.resources.linux.doctree | Bin 0 -> 433963 bytes .../nepi.resources.linux.netns.doctree | Bin 0 -> 54967 bytes .../nepi.resources.linux.ns3.ccn.doctree | Bin 0 -> 30797 bytes .../_layout/nepi.resources.linux.ns3.doctree | Bin 0 -> 127381 bytes .../_layout/nepi.resources.netns.doctree | Bin 0 -> 152253 bytes .../nepi.resources.ns3.classes.doctree | Bin 0 -> 490090 bytes .../_layout/nepi.resources.ns3.doctree | Bin 0 -> 377819 bytes .../_layout/nepi.resources.omf.doctree | Bin 0 -> 373627 bytes .../_layout/nepi.resources.planetlab.doctree | Bin 0 -> 143676 bytes .../nepi.resources.planetlab.ns3.doctree | Bin 0 -> 16927 bytes ...pi.resources.planetlab.openvswitch.doctree | Bin 0 -> 59649 bytes .../_build/doctrees/_layout/nepi.util.doctree | Bin 0 -> 315318 bytes .../_layout/nepi.util.parsers.doctree | Bin 0 -> 15545 bytes doc/sphinx/_build/doctrees/environment.pickle | Bin 0 -> 3275437 bytes doc/sphinx/_build/doctrees/index.doctree | Bin 0 -> 21584 bytes doc/sphinx/_build/html/.buildinfo | 4 + doc/sphinx/_build/html/_layout/modules.html | 150 + doc/sphinx/_build/html/_layout/nepi.data.html | 134 + .../_layout/nepi.data.processing.ccn.html | 174 + .../html/_layout/nepi.data.processing.html | 127 + .../_layout/nepi.data.processing.ping.html | 133 + .../_build/html/_layout/nepi.execution.html | 2376 +++++ doc/sphinx/_build/html/_layout/nepi.html | 483 + .../html/_layout/nepi.resources.all.html | 165 + .../_build/html/_layout/nepi.resources.html | 409 + .../_layout/nepi.resources.linux.ccn.html | 446 + .../html/_layout/nepi.resources.linux.html | 1539 +++ .../_layout/nepi.resources.linux.netns.html | 285 + .../_layout/nepi.resources.linux.ns3.ccn.html | 186 + .../_layout/nepi.resources.linux.ns3.html | 536 + .../html/_layout/nepi.resources.netns.html | 617 ++ .../_layout/nepi.resources.ns3.classes.html | 1171 ++ .../html/_layout/nepi.resources.ns3.html | 1239 +++ .../html/_layout/nepi.resources.omf.html | 1597 +++ .../_layout/nepi.resources.planetlab.html | 629 ++ .../_layout/nepi.resources.planetlab.ns3.html | 153 + .../nepi.resources.planetlab.openvswitch.html | 321 + doc/sphinx/_build/html/_layout/nepi.util.html | 1227 +++ .../html/_layout/nepi.util.parsers.html | 151 + doc/sphinx/_build/html/_modules/index.html | 330 + .../nepi/data/processing/ccn/parser.html | 505 + .../nepi/data/processing/ping/parser.html | 212 + .../_modules/nepi/execution/attribute.html | 286 + .../html/_modules/nepi/execution/ec.html | 1365 +++ .../_modules/nepi/execution/resource.html | 1326 +++ .../html/_modules/nepi/execution/runner.html | 267 + .../_modules/nepi/execution/scheduler.html | 201 + .../html/_modules/nepi/execution/trace.html | 148 + .../nepi/resources/all/collector.html | 227 + .../nepi/resources/linux/application.html | 860 ++ .../resources/linux/ccn/ccnapplication.html | 159 + .../nepi/resources/linux/ccn/ccncat.html | 163 + .../nepi/resources/linux/ccn/ccncontent.html | 241 + .../nepi/resources/linux/ccn/ccnd.html | 442 + .../nepi/resources/linux/ccn/ccnpeek.html | 155 + .../nepi/resources/linux/ccn/ccnping.html | 186 + .../resources/linux/ccn/ccnpingserver.html | 225 + .../nepi/resources/linux/ccn/ccnpoke.html | 163 + .../nepi/resources/linux/ccn/ccnr.html | 397 + .../nepi/resources/linux/ccn/fibentry.html | 367 + .../nepi/resources/linux/channel.html | 129 + .../nepi/resources/linux/debfuncs.html | 133 + .../nepi/resources/linux/gretunnel.html | 177 + .../nepi/resources/linux/interface.html | 402 + .../_modules/nepi/resources/linux/mtr.html | 240 + .../resources/linux/netns/netnsclient.html | 198 + .../resources/linux/netns/netnsemulation.html | 473 + .../_modules/nepi/resources/linux/node.html | 1216 +++ .../_modules/nepi/resources/linux/nping.html | 312 + .../ns3/ccn/ns3ccncatdceapplication.html | 153 + .../linux/ns3/ccn/ns3ccndceapplication.html | 198 + .../linux/ns3/ccn/ns3ccnddceapplication.html | 295 + .../ns3/ccn/ns3ccnpeekdceapplication.html | 136 + .../ns3/ccn/ns3ccnpokedceapplication.html | 155 + .../linux/ns3/ccn/ns3ccnrdceapplication.html | 319 + .../ns3/ccn/ns3fibentrydceapplication.html | 196 + .../nepi/resources/linux/ns3/fdudptunnel.html | 473 + .../nepi/resources/linux/ns3/ns3client.html | 208 + .../linux/ns3/ns3dceapplication.html | 170 + .../linux/ns3/ns3pingdceapplication.html | 345 + .../resources/linux/ns3/ns3simulation.html | 827 ++ .../resources/linux/ns3/tuntapfdlink.html | 251 + .../_modules/nepi/resources/linux/ping.html | 372 + .../_modules/nepi/resources/linux/route.html | 251 + .../nepi/resources/linux/rpmfuncs.html | 161 + .../_modules/nepi/resources/linux/tap.html | 710 ++ .../nepi/resources/linux/tcpdump.html | 499 + .../nepi/resources/linux/traceroute.html | 217 + .../_modules/nepi/resources/linux/tun.html | 127 + .../_modules/nepi/resources/linux/tunnel.html | 256 + .../nepi/resources/linux/udptest.html | 461 + .../nepi/resources/linux/udptunnel.html | 245 + .../resources/netns/netnsapplication.html | 190 + .../nepi/resources/netns/netnsbase.html | 230 + .../nepi/resources/netns/netnsclient.html | 132 + .../nepi/resources/netns/netnsemulation.html | 132 + .../nepi/resources/netns/netnsinterface.html | 117 + .../resources/netns/netnsipv4address.html | 153 + .../nepi/resources/netns/netnsnode.html | 137 + .../resources/netns/netnsnodeinterface.html | 157 + .../nepi/resources/netns/netnsroute.html | 152 + .../nepi/resources/netns/netnsserver.html | 307 + .../nepi/resources/netns/netnsswitch.html | 153 + .../nepi/resources/netns/netnswrapper.html | 280 + .../resources/netns/netnswrapper_debug.html | 251 + .../ns3/classes/aarf_wifi_manager.html | 268 + .../ns3/classes/aarfcd_wifi_manager.html | 308 + .../resources/ns3/classes/adhoc_wifi_mac.html | 300 + .../ns3/classes/aloha_noack_net_device.html | 168 + .../ns3/classes/amrr_wifi_manager.html | 268 + .../resources/ns3/classes/ap_wifi_mac.html | 340 + .../ns3/classes/arf_wifi_manager.html | 238 + .../resources/ns3/classes/arp_l3protocol.html | 146 + .../ns3/classes/base_station_net_device.html | 260 + .../ns3/classes/binary_error_model.html | 141 + .../classes/binary_error_sixlow_model.html | 141 + .../resources/ns3/classes/bridge_channel.html | 141 + .../ns3/classes/bridge_net_device.html | 161 + .../ns3/classes/bulk_send_application.html | 196 + .../ns3/classes/burst_error_model.html | 171 + .../ns3/classes/cara_wifi_manager.html | 258 + .../constant_acceleration_mobility_model.html | 156 + .../constant_position_mobility_model.html | 156 + .../classes/constant_rate_wifi_manager.html | 238 + ...onstant_speed_propagation_delay_model.html | 141 + .../constant_velocity_mobility_model.html | 156 + .../cost231propagation_loss_model.html | 181 + .../resources/ns3/classes/csma_channel.html | 161 + .../ns3/classes/csma_net_device.html | 220 + .../ns3/classes/drop_tail_queue.html | 164 + .../resources/ns3/classes/dsrdsr_routing.html | 540 + .../resources/ns3/classes/emu_net_device.html | 216 + .../resources/ns3/classes/error_channel.html | 141 + .../ns3/classes/error_channel_sixlow.html | 141 + .../ns3/classes/error_net_device.html | 135 + .../resources/ns3/classes/fd_net_device.html | 206 + .../ns3/classes/fixed_rss_loss_model.html | 141 + .../classes/friis_propagation_loss_model.html | 161 + .../classes/gauss_markov_mobility_model.html | 246 + .../classes/hierarchical_mobility_model.html | 156 + ...brid_buildings_propagation_loss_model.html | 181 + .../ns3/classes/icmpv4l4protocol.html | 141 + .../ns3/classes/icmpv6l4protocol.html | 161 + .../ns3/classes/ideal_wifi_manager.html | 228 + .../resources/ns3/classes/ipv4l3protocol.html | 206 + .../itu_r1411los_propagation_loss_model.html | 130 + ...s_over_rooftop_propagation_loss_model.html | 201 + .../classes/jakes_propagation_loss_model.html | 130 + .../kun2600mhz_propagation_loss_model.html | 130 + .../ns3/classes/list_error_model.html | 141 + .../log_distance_propagation_loss_model.html | 161 + .../ns3/classes/loopback_net_device.html | 130 + .../ns3/classes/lr_wpan_net_device.html | 141 + .../ns3/classes/lte_enb_net_device.html | 211 + .../ns3/classes/lte_simple_net_device.html | 135 + .../ns3/classes/lte_ue_net_device.html | 171 + .../matrix_propagation_loss_model.html | 141 + .../ns3/classes/mesh_point_device.html | 141 + .../ns3/classes/mesh_wifi_interface_mac.html | 330 + .../ns3/classes/minstrel_wifi_manager.html | 268 + .../classes/multi_model_spectrum_channel.html | 156 + .../nakagami_propagation_loss_model.html | 201 + .../ns3/classes/nist_error_rate_model.html | 130 + .../nepi/resources/ns3/classes/node.html | 151 + .../classes/non_communicating_net_device.html | 130 + .../resources/ns3/classes/ocb_wifi_mac.html | 300 + .../oh_buildings_propagation_loss_model.html | 171 + .../okumura_hata_propagation_loss_model.html | 161 + .../ns3/classes/on_off_application.html | 226 + .../ns3/classes/onoe_wifi_manager.html | 248 + .../resources/ns3/classes/packet_sink.html | 176 + .../nepi/resources/ns3/classes/ping6.html | 201 + .../ns3/classes/point_to_point_channel.html | 156 + .../classes/point_to_point_net_device.html | 216 + .../point_to_point_remote_channel.html | 156 + .../nepi/resources/ns3/classes/radvd.html | 161 + .../random_direction2d_mobility_model.html | 186 + .../random_propagation_delay_model.html | 141 + .../random_propagation_loss_model.html | 141 + .../classes/random_walk2d_mobility_model.html | 216 + .../random_waypoint_mobility_model.html | 176 + .../classes/range_propagation_loss_model.html | 141 + .../ns3/classes/rate_error_model.html | 171 + .../ns3/classes/receive_list_error_model.html | 141 + .../nepi/resources/ns3/classes/red_queue.html | 264 + .../ns3/classes/rraa_wifi_manager.html | 458 + .../resources/ns3/classes/simple_channel.html | 141 + .../ns3/classes/simple_net_device.html | 135 + .../single_model_spectrum_channel.html | 156 + .../ns3/classes/six_low_pan_net_device.html | 214 + .../resources/ns3/classes/sta_wifi_mac.html | 348 + ..._state_random_waypoint_mobility_model.html | 246 + .../subscriber_station_net_device.html | 306 + .../resources/ns3/classes/tap_bridge.html | 211 + .../resources/ns3/classes/tcp_l4protocol.html | 161 + ...e_log_distance_propagation_loss_model.html | 201 + ...two_ray_ground_propagation_loss_model.html | 171 + .../resources/ns3/classes/uan_channel.html | 141 + .../resources/ns3/classes/udp_client.html | 201 + .../ns3/classes/udp_echo_client.html | 206 + .../ns3/classes/udp_echo_server.html | 161 + .../resources/ns3/classes/udp_l4protocol.html | 141 + .../resources/ns3/classes/udp_server.html | 171 + .../ns3/classes/udp_trace_client.html | 181 + .../nepi/resources/ns3/classes/v4ping.html | 196 + .../ns3/classes/virtual_net_device.html | 162 + .../ns3/classes/waypoint_mobility_model.html | 186 + .../ns3/classes/wifi_net_device.html | 141 + .../ns3/classes/yans_error_rate_model.html | 130 + .../ns3/classes/yans_wifi_channel.html | 141 + .../resources/ns3/classes/yans_wifi_phy.html | 344 + .../nepi/resources/ns3/ns3application.html | 181 + .../nepi/resources/ns3/ns3arpl3protocol.html | 137 + .../_modules/nepi/resources/ns3/ns3base.html | 257 + .../resources/ns3/ns3ccndceapplication.html | 212 + .../nepi/resources/ns3/ns3channel.html | 141 + .../nepi/resources/ns3/ns3client.html | 141 + .../nepi/resources/ns3/ns3dceapplication.html | 272 + .../nepi/resources/ns3/ns3dcehelper.html | 149 + .../nepi/resources/ns3/ns3errormodel.html | 140 + .../nepi/resources/ns3/ns3errorratemodel.html | 144 + .../nepi/resources/ns3/ns3fdnetdevice.html | 149 + .../resources/ns3/ns3icmpv4l4protocol.html | 134 + .../nepi/resources/ns3/ns3ipv4l3protocol.html | 157 + .../nepi/resources/ns3/ns3mobilitymodel.html | 135 + .../nepi/resources/ns3/ns3netdevice.html | 313 + .../_modules/nepi/resources/ns3/ns3node.html | 285 + .../nepi/resources/ns3/ns3pipechanel.html | 171 + .../ns3/ns3propagationdelaymodel.html | 144 + .../ns3/ns3propagationlossmodel.html | 144 + .../_modules/nepi/resources/ns3/ns3queue.html | 145 + .../_modules/nepi/resources/ns3/ns3route.html | 183 + .../nepi/resources/ns3/ns3server.html | 349 + .../nepi/resources/ns3/ns3simulation.html | 141 + .../nepi/resources/ns3/ns3wifichannel.html | 141 + .../nepi/resources/ns3/ns3wifimac.html | 169 + .../nepi/resources/ns3/ns3wifinetdevice.html | 144 + .../nepi/resources/ns3/ns3wifiphy.html | 178 + .../ns3/ns3wifiremotestationmanager.html | 145 + .../nepi/resources/ns3/ns3wrapper.html | 795 ++ .../nepi/resources/ns3/ns3wrapper_debug.html | 271 + .../ns3/resource_manager_generator.html | 330 + .../nepi/resources/omf/application.html | 510 + .../_modules/nepi/resources/omf/channel.html | 291 + .../nepi/resources/omf/interface.html | 430 + .../nepi/resources/omf/messages_5_4.html | 345 + .../nepi/resources/omf/messages_6.html | 343 + .../_modules/nepi/resources/omf/node.html | 267 + .../_modules/nepi/resources/omf/omf5_api.html | 402 + .../_modules/nepi/resources/omf/omf6_api.html | 351 + .../nepi/resources/omf/omf6_parser.html | 382 + .../nepi/resources/omf/omf_api_factory.html | 230 + .../nepi/resources/omf/omf_client.html | 449 + .../nepi/resources/omf/omf_resource.html | 167 + .../nepi/resources/omf/wilabt_node.html | 559 + .../nepi/resources/planetlab/node.html | 775 ++ .../resources/planetlab/ns3/fdudptunnel.html | 164 + .../resources/planetlab/ns3/tuntapfdlink.html | 183 + .../resources/planetlab/openvswitch/ovs.html | 406 + .../planetlab/openvswitch/ovsport.html | 384 + .../nepi/resources/planetlab/plcapi.html | 676 ++ .../nepi/resources/planetlab/sfa_node.html | 762 ++ .../nepi/resources/planetlab/tap.html | 413 + .../nepi/resources/planetlab/tun.html | 129 + .../nepi/resources/planetlab/vroute.html | 276 + .../html/_modules/nepi/util/environ.html | 293 + .../html/_modules/nepi/util/execfuncs.html | 356 + .../_build/html/_modules/nepi/util/guid.html | 123 + .../html/_modules/nepi/util/logger.html | 145 + .../html/_modules/nepi/util/manifoldapi.html | 361 + .../html/_modules/nepi/util/netgraph.html | 434 + .../html/_modules/nepi/util/parallel.html | 255 + .../nepi/util/parsers/xml_parser.html | 549 + .../html/_modules/nepi/util/plotter.html | 198 + .../html/_modules/nepi/util/rmatcher.html | 155 + .../html/_modules/nepi/util/serializer.html | 151 + .../html/_modules/nepi/util/sfaapi.html | 562 + .../_modules/nepi/util/sfarspec_proc.html | 312 + .../html/_modules/nepi/util/sshfuncs.html | 988 ++ .../html/_modules/nepi/util/statfuncs.html | 136 + .../html/_modules/nepi/util/timefuncs.html | 213 + .../_build/html/_sources/_layout/modules.txt | 7 + .../_layout/nepi.data.processing.ccn.txt | 22 + .../_layout/nepi.data.processing.ping.txt | 22 + .../_sources/_layout/nepi.data.processing.txt | 18 + .../html/_sources/_layout/nepi.data.txt | 17 + .../html/_sources/_layout/nepi.execution.txt | 70 + .../_sources/_layout/nepi.resources.all.txt | 22 + .../_layout/nepi.resources.linux.ccn.txt | 94 + .../_layout/nepi.resources.linux.netns.txt | 30 + .../_layout/nepi.resources.linux.ns3.ccn.txt | 70 + .../_layout/nepi.resources.linux.ns3.txt | 69 + .../_sources/_layout/nepi.resources.linux.txt | 167 + .../_sources/_layout/nepi.resources.netns.txt | 118 + .../_layout/nepi.resources.ns3.classes.txt | 862 ++ .../_sources/_layout/nepi.resources.ns3.txt | 269 + .../_sources/_layout/nepi.resources.omf.txt | 118 + .../_layout/nepi.resources.planetlab.ns3.txt | 30 + .../nepi.resources.planetlab.openvswitch.txt | 30 + .../_layout/nepi.resources.planetlab.txt | 70 + .../html/_sources/_layout/nepi.resources.txt | 22 + .../_build/html/_sources/_layout/nepi.txt | 20 + .../_sources/_layout/nepi.util.parsers.txt | 22 + .../html/_sources/_layout/nepi.util.txt | 141 + doc/sphinx/_build/html/_sources/index.txt | 91 + .../_build/html/_static/ajax-loader.gif | Bin 0 -> 673 bytes doc/sphinx/_build/html/_static/basic.css | 537 + .../_build/html/_static/comment-bright.png | Bin 0 -> 3500 bytes .../_build/html/_static/comment-close.png | Bin 0 -> 3578 bytes doc/sphinx/_build/html/_static/comment.png | Bin 0 -> 3445 bytes doc/sphinx/_build/html/_static/contents.png | Bin 0 -> 202 bytes doc/sphinx/_build/html/_static/doctools.js | 238 + .../_build/html/_static/down-pressed.png | Bin 0 -> 368 bytes doc/sphinx/_build/html/_static/down.png | Bin 0 -> 363 bytes doc/sphinx/_build/html/_static/file.png | Bin 0 -> 392 bytes doc/sphinx/_build/html/_static/jquery.js | 9404 +++++++++++++++++ doc/sphinx/_build/html/_static/minus.png | Bin 0 -> 199 bytes doc/sphinx/_build/html/_static/navigation.png | Bin 0 -> 218 bytes doc/sphinx/_build/html/_static/plus.png | Bin 0 -> 199 bytes doc/sphinx/_build/html/_static/pygments.css | 62 + doc/sphinx/_build/html/_static/searchtools.js | 622 ++ doc/sphinx/_build/html/_static/sphinxdoc.css | 339 + doc/sphinx/_build/html/_static/underscore.js | 1226 +++ doc/sphinx/_build/html/_static/up-pressed.png | Bin 0 -> 372 bytes doc/sphinx/_build/html/_static/up.png | Bin 0 -> 363 bytes doc/sphinx/_build/html/_static/websupport.js | 808 ++ doc/sphinx/_build/html/genindex.html | 7100 +++++++++++++ doc/sphinx/_build/html/index.html | 201 + doc/sphinx/_build/html/objects.inv | Bin 0 -> 16497 bytes doc/sphinx/_build/html/py-modindex.html | 1424 +++ doc/sphinx/_build/html/search.html | 105 + doc/sphinx/_build/html/searchindex.js | 1 + doc/sphinx/_layout/modules.rst | 7 + .../_layout/nepi.data.processing.ccn.rst | 22 + .../_layout/nepi.data.processing.ping.rst | 22 + doc/sphinx/_layout/nepi.data.processing.rst | 18 + doc/sphinx/_layout/nepi.data.rst | 17 + doc/sphinx/_layout/nepi.execution.rst | 70 + doc/sphinx/_layout/nepi.resources.all.rst | 22 + .../_layout/nepi.resources.linux.ccn.rst | 94 + .../_layout/nepi.resources.linux.netns.rst | 30 + .../_layout/nepi.resources.linux.ns3.ccn.rst | 70 + .../_layout/nepi.resources.linux.ns3.rst | 69 + doc/sphinx/_layout/nepi.resources.linux.rst | 167 + doc/sphinx/_layout/nepi.resources.netns.rst | 118 + .../_layout/nepi.resources.ns3.classes.rst | 862 ++ doc/sphinx/_layout/nepi.resources.ns3.rst | 269 + doc/sphinx/_layout/nepi.resources.omf.rst | 118 + .../_layout/nepi.resources.planetlab.ns3.rst | 30 + .../nepi.resources.planetlab.openvswitch.rst | 30 + .../_layout/nepi.resources.planetlab.rst | 70 + doc/sphinx/_layout/nepi.resources.rst | 22 + doc/sphinx/_layout/nepi.rst | 20 + doc/sphinx/_layout/nepi.util.parsers.rst | 22 + doc/sphinx/_layout/nepi.util.rst | 141 + doc/sphinx/conf.py | 247 + doc/sphinx/index.rst | 91 + 368 files changed, 103370 insertions(+) create mode 100644 doc/sphinx/Makefile create mode 100644 doc/sphinx/_build/doctrees/_layout/modules.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.data.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.data.processing.ccn.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.data.processing.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.data.processing.ping.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.execution.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.all.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.ccn.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.netns.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.ns3.ccn.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.ns3.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.netns.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.ns3.classes.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.ns3.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.omf.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.ns3.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.openvswitch.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.util.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.util.parsers.doctree create mode 100644 doc/sphinx/_build/doctrees/environment.pickle create mode 100644 doc/sphinx/_build/doctrees/index.doctree create mode 100644 doc/sphinx/_build/html/.buildinfo create mode 100644 doc/sphinx/_build/html/_layout/modules.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.data.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.data.processing.ccn.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.data.processing.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.data.processing.ping.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.execution.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.all.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.linux.ccn.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.linux.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.linux.netns.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.ccn.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.netns.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.ns3.classes.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.ns3.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.omf.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.planetlab.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.planetlab.ns3.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.planetlab.openvswitch.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.util.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.util.parsers.html create mode 100644 doc/sphinx/_build/html/_modules/index.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/data/processing/ccn/parser.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/data/processing/ping/parser.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/execution/attribute.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/execution/ec.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/execution/resource.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/execution/runner.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/execution/scheduler.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/execution/trace.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/all/collector.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/application.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncat.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncontent.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnd.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpeek.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnping.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpingserver.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpoke.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnr.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/fibentry.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/debfuncs.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/gretunnel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/interface.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/mtr.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsclient.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsemulation.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/nping.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccncatdceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccndceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnddceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpeekdceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpokedceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnrdceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3fibentrydceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/fdudptunnel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3client.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3dceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3pingdceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3simulation.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/tuntapfdlink.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ping.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/route.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/rpmfuncs.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/tap.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/tcpdump.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/traceroute.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/tun.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/tunnel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/udptest.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/udptunnel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsbase.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsclient.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsemulation.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsinterface.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsipv4address.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnode.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnodeinterface.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsroute.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsserver.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsswitch.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper_debug.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarf_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarfcd_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/adhoc_wifi_mac.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aloha_noack_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/amrr_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ap_wifi_mac.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arf_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arp_l3protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/base_station_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_sixlow_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bulk_send_application.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/burst_error_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cara_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_acceleration_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_position_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_rate_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_speed_propagation_delay_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_velocity_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cost231propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/drop_tail_queue.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/dsrdsr_routing.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/emu_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel_sixlow.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fd_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fixed_rss_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/friis_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/gauss_markov_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hierarchical_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hybrid_buildings_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv4l4protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv6l4protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ideal_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ipv4l3protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411los_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411nlos_over_rooftop_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/jakes_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/kun2600mhz_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/list_error_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/log_distance_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/loopback_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lr_wpan_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_enb_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_simple_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_ue_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/matrix_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_point_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_wifi_interface_mac.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/minstrel_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/multi_model_spectrum_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nakagami_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nist_error_rate_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/non_communicating_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ocb_wifi_mac.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/oh_buildings_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/okumura_hata_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/on_off_application.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/onoe_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/packet_sink.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ping6.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_remote_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/radvd.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_direction2d_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_delay_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_walk2d_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_waypoint_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/range_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rate_error_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/receive_list_error_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/red_queue.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rraa_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/single_model_spectrum_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/six_low_pan_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/sta_wifi_mac.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/steady_state_random_waypoint_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/subscriber_station_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tap_bridge.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tcp_l4protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/three_log_distance_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/two_ray_ground_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/uan_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_client.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_client.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_server.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_l4protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_server.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_trace_client.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/v4ping.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/virtual_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/waypoint_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/wifi_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_error_rate_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_phy.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3application.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3arpl3protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3base.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ccndceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3client.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dcehelper.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errormodel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errorratemodel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3fdnetdevice.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3icmpv4l4protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ipv4l3protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3mobilitymodel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3netdevice.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3pipechanel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationdelaymodel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationlossmodel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3queue.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3route.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3server.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3simulation.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifichannel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifimac.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifinetdevice.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiphy.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiremotestationmanager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper_debug.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/resource_manager_generator.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/application.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/interface.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_5_4.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_6.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/omf5_api.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_api.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_parser.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_api_factory.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_client.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_resource.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/wilabt_node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/fdudptunnel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/tuntapfdlink.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovs.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovsport.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/plcapi.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/sfa_node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tap.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tun.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/vroute.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/environ.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/execfuncs.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/guid.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/logger.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/manifoldapi.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/netgraph.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/parallel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/parsers/xml_parser.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/plotter.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/rmatcher.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/serializer.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/sfaapi.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/sfarspec_proc.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/sshfuncs.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/statfuncs.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/timefuncs.html create mode 100644 doc/sphinx/_build/html/_sources/_layout/modules.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ccn.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ping.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.data.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.execution.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.all.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ccn.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.netns.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.ccn.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.netns.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.classes.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.omf.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.ns3.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.openvswitch.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.util.parsers.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.util.txt create mode 100644 doc/sphinx/_build/html/_sources/index.txt create mode 100644 doc/sphinx/_build/html/_static/ajax-loader.gif create mode 100644 doc/sphinx/_build/html/_static/basic.css create mode 100644 doc/sphinx/_build/html/_static/comment-bright.png create mode 100644 doc/sphinx/_build/html/_static/comment-close.png create mode 100644 doc/sphinx/_build/html/_static/comment.png create mode 100644 doc/sphinx/_build/html/_static/contents.png create mode 100644 doc/sphinx/_build/html/_static/doctools.js create mode 100644 doc/sphinx/_build/html/_static/down-pressed.png create mode 100644 doc/sphinx/_build/html/_static/down.png create mode 100644 doc/sphinx/_build/html/_static/file.png create mode 100644 doc/sphinx/_build/html/_static/jquery.js create mode 100644 doc/sphinx/_build/html/_static/minus.png create mode 100644 doc/sphinx/_build/html/_static/navigation.png create mode 100644 doc/sphinx/_build/html/_static/plus.png create mode 100644 doc/sphinx/_build/html/_static/pygments.css create mode 100644 doc/sphinx/_build/html/_static/searchtools.js create mode 100644 doc/sphinx/_build/html/_static/sphinxdoc.css create mode 100644 doc/sphinx/_build/html/_static/underscore.js create mode 100644 doc/sphinx/_build/html/_static/up-pressed.png create mode 100644 doc/sphinx/_build/html/_static/up.png create mode 100644 doc/sphinx/_build/html/_static/websupport.js create mode 100644 doc/sphinx/_build/html/genindex.html create mode 100644 doc/sphinx/_build/html/index.html create mode 100644 doc/sphinx/_build/html/objects.inv create mode 100644 doc/sphinx/_build/html/py-modindex.html create mode 100644 doc/sphinx/_build/html/search.html create mode 100644 doc/sphinx/_build/html/searchindex.js create mode 100644 doc/sphinx/_layout/modules.rst create mode 100644 doc/sphinx/_layout/nepi.data.processing.ccn.rst create mode 100644 doc/sphinx/_layout/nepi.data.processing.ping.rst create mode 100644 doc/sphinx/_layout/nepi.data.processing.rst create mode 100644 doc/sphinx/_layout/nepi.data.rst create mode 100644 doc/sphinx/_layout/nepi.execution.rst create mode 100644 doc/sphinx/_layout/nepi.resources.all.rst create mode 100644 doc/sphinx/_layout/nepi.resources.linux.ccn.rst create mode 100644 doc/sphinx/_layout/nepi.resources.linux.netns.rst create mode 100644 doc/sphinx/_layout/nepi.resources.linux.ns3.ccn.rst create mode 100644 doc/sphinx/_layout/nepi.resources.linux.ns3.rst create mode 100644 doc/sphinx/_layout/nepi.resources.linux.rst create mode 100644 doc/sphinx/_layout/nepi.resources.netns.rst create mode 100644 doc/sphinx/_layout/nepi.resources.ns3.classes.rst create mode 100644 doc/sphinx/_layout/nepi.resources.ns3.rst create mode 100644 doc/sphinx/_layout/nepi.resources.omf.rst create mode 100644 doc/sphinx/_layout/nepi.resources.planetlab.ns3.rst create mode 100644 doc/sphinx/_layout/nepi.resources.planetlab.openvswitch.rst create mode 100644 doc/sphinx/_layout/nepi.resources.planetlab.rst create mode 100644 doc/sphinx/_layout/nepi.resources.rst create mode 100644 doc/sphinx/_layout/nepi.rst create mode 100644 doc/sphinx/_layout/nepi.util.parsers.rst create mode 100644 doc/sphinx/_layout/nepi.util.rst create mode 100644 doc/sphinx/conf.py create mode 100644 doc/sphinx/index.rst diff --git a/doc/sphinx/Makefile b/doc/sphinx/Makefile new file mode 100644 index 00000000..99929ff3 --- /dev/null +++ b/doc/sphinx/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Nepi.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Nepi.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Nepi" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Nepi" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/doc/sphinx/_build/doctrees/_layout/modules.doctree b/doc/sphinx/_build/doctrees/_layout/modules.doctree new file mode 100644 index 0000000000000000000000000000000000000000..ec30cb7990d5858b8a0c9e043293b20687cb47e3 GIT binary patch literal 2721 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 W&Hr@xUo>t72%G=!od1)xm;MJLc_csp literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.data.processing.ccn.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.data.processing.ccn.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a5a881750c431e87f2d31aed91653c304dd10e25 GIT binary patch literal 23918 zcmd5^2Y4JsvUZXz$(EeRV7w$r23sO$FkrGl#DOJ^n&Y9!=RXsC1o2>P{@8S2!o}THduBxu?uD@n>rVkwvi)UiFY$9d1 zr89BUZs5yaGo5Wv!>7(wBOEod)u>NLd(G@XpJ}U6j;d)5uR3hlu(a8iXp2X)(Y8Ly z#7x^xq9t^Md z-^);SgW(1=w{u;+nRqURp44}Q$Du}FhFqPtYUl{BU4@=_uD7q)P&H;S99lrzP+v55 zK(xnHV>_zyV8Rv+lu4<^!K$oEWuoyCtC|MGt1rMRZ@i-EbS4|knvqyK!c#$w8w@uO z-7cgZsK$4Mrw`4|6C{H963@jB)? z%B|JX9md3HE}QAjWU}y`8L_ib%Bp2%4L3&fib=$6wXCC-Yqe_eHyVF+_^US>0<&lX6B~%u1x<=&D+wQ>|DW5^OWZ{cTVyAtJ2os8tXVC_2Y=O0zM{sD=07 zC)Hw&FlycU*6`LCrFJXRYqm#IiFCA`%)X4>&K9;K%Cy^kRwCWs9!W(9GP$hOmyIW6 zXVp|=bT-<oi8kQc>H+d3&c( z*M-$bJm9N$8Y6jZ*637gT2rD%jpkpgQ>|@{jpmF|u+~)T%o+h867&5oR_Hh0t(Fw$cE8|1p8xh{)`b*7`XM71$2ZQr8CJ;TzV2a-m%i3{ zeciKFIvaM>UfkJ*h?0B5^j(6E*r&ii*Ac#=ec_0OklqO=?dPZnJBc-g#Yr)}(AuK$ zxQ6&dI&StisQocsQAc%oj)PrB{l*;7FzYu}F`k&hs^UBm%vPR{n3Z~Zu7%ZwB~J;{ z?o{2aSoXkwV0}-xb?D$6YSlw9bs>hs7?xF*jKgqu958jc4+%#l1APb|TsiF66m#Pb zVrqLnrnV!dwtIQYz=r6*jh>}@LYZ!f!DZu;%U_B!2Ux3G;mc}xXo@>&N7HmGCa%Hte$ zJi9V9w7qTc*g=R-?545eCRdU=ft_?>nP}zBI&~6)RW&NqU*VIJ9d(K~4Ua1yrbNB& z#i{7UX^uJ_Ev&(SiS<5@`WxGK#)9lS6ZVz&^I0(HY)AdwGw8Gh7=(!i$7W4R;qIhC zode6xb<}xYQ_p!5#j*lsbv~Q;j|G`{L51P;U>sp z4Rl@WsOvmkSBNgllYPCTZeZDqLpC&*E@RepV?|vzL0845>SpNvx1(4`~~XF{p>>sYEQ1ou9{YX2;!2kC_$xj_45RW$P8u(x^eZMBEz8VO8G7GwtEx zpqWT>I^CciK}R2T)MI`}A9sgTJz+F@{hSWo1JskzK=#{W-OF;Ha%b>9`u3tzJ&lol z#!=6Dqx7hr!L?eSdQM-C4SHKWkIGzExsjLU>fV4gs25=Ci;jB9lMN6FghZE3z06bL zmC}jn1F?Fw*crUCWc@U#*P!EdN4)_Z;Y~30H;>2d(9D?~-lK?+`}iZ&ouQB!jaebi z-a^O>vX&XjX8JN%%mW(#+SHry|BJAa;k@40qTXT?-!5a~EH8;t@4&JDd;RZXG~RR6 z`{<3uw!AK$*3OnJ?E^=B=(!V_CKi;=kv>{Lj`T6-NSnep!5oRbu#hRzI8Kp1DNK

D`S1mbth#A<}9|DZd6 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%0Ai-Csqris` zBB(j(>S2S#QSt!k3}HD_v#^UiJFqvG?4Cep39Vwbceapw!Yg3vSGpz7@5ROY84clD zPV@c_q2f?)3kiARg^`W&&6F`FOVPB=j~`80n&}FE`_KtpE{GB1`a%px2j%3V5)0~70PGn>WcF*esSS*O=(}Gr~I|@zy19T6cH>RTLo*Z`RL_@q^e=paKFw=A&pVZ^qeG~g|_V&^JxMurhj3Oy>wwa;_ zP=|dT$D*g$1r+;@VP8vnP#7DmXe#TnJ;ZD^Mx$$=-b9ifW+1q9Ej2XZqdCN4j^f>D0 z8yOPTptsXRu9AqaKS9n+Wmk zz03TJW^S4jr8MtK1i5Ckm!1{g#d+BH(K`=*By0AfE12%jfoRl$Hhq=V*N)Tkd^y4F zPhg`|EUujGdhrDoU1QV&0=pAE^rDEAF~{Vdov;(w-IrdH+Qnmdx8s0_iT#RF5o|d| z*oPI<CjmhY0uOAKa(bAq?w*guZl3;@jlzk#nH>&6ul5qqk9Q z)a0_=)7PhW_`Jat#f#`&Eh&)>4l=#RZ1vJ)I`+b&_xXApHo3E-T^In@i62PYdIXw2 zSdr+b51EZuT(m1PClSwD^bu-i)fr8NlaxMY#u{Vytzpt9d_LOU)|NiSl{M8Ehs~d| z*iMw!BOIHh&rm;T)c2T(hfyA@&r#8V?elo=#AQ- z#rPnu^ke#OEIZd_EMAOavavAz&W(o2-nH}}oICUfj;)qayvvjZjs_Zrok@`83`c=C z{c&_taDKzY;{82qH7AV(jqkZe2@ld5JkhA(I)iuO!Zx5b@`6F$l~(UZn@4`DR{t_T zTHl%1$;0_1CtyiedoAQ(vmBAE@4wt+3I-%S#dQJ2^*9#^L+YN4O=Uyq%ozRE#{~Vw zVxxX-xJkchHV#{vOu@iH^aN*E+9CKZ5{{zHQfeQct literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.data.processing.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.data.processing.doctree new file mode 100644 index 0000000000000000000000000000000000000000..70a98ba2708b67a68680dcb90466861df21f3295 GIT binary patch literal 3739 zcmai12YVb>6_sU6+Fe!4b_kJVE5&#XNNY&IAtV6;7>LMH;u{pgFwD-p-8Xo4X70Q< zD!`B!h>_^M_fF`&_uhN&{b#^=GqWm768n?CPrG_^-?`_Wd+(Xs23;?5Q|$+8F^oK+ zYUX2Cgu2Fij-TbhjQ7^58aiE}*JGi0U&cfA<;j78fo|lbftYurP~*7b;pXxvzE)`~ zcHA>g2Zu+R%d_|@6tTbPIoer_lgJfH`C(_iJj9h|O8fDU(!K_cD6~D%R$R@vMia4< zC}DT;NFHz0;xU?V(Sam>>^(WGf7)loZ&bQo!2EA1qjCztln zh)Kiu6i;Qmzb=PqvdCd!D~D-0LZdq~I3O!DYw#}^{0rOo7kc;)rc`mIA9%pThb+FJ zpHL-S1FXjP0G}6Td{6M1IIAW4i)es`ktP!2897M9<@dA8*MYf)jJl%X1b*l=5)ntL zVX!n%qlSv5AFeg*z*&z{oqylY@nWJh&(Vl>Iwo^IOd};2K0-A|>%?!R8g-h__~JTM zyfilF6klS|h#NRc;rB}|s$2jcv=2xHA72_o zuu?~SZ#gKz%YEwo#Gv4TsPTP4%RTZc46VGo-9(8d5#a= z6}QZBE84^4<^LDrI-q}e#*Z-QO}J}v^!;SGQ8$j#(5vwy0q0c4kLsmWUJrqnNBGeu z!N-(9_edOe9Jk0 zilE^Vy|qbWWj<{`z_m}c*sjZ)6LU1!Y`v6lR_>;H>?MnofMsl1q?RHKt|t4Cnj zAcY#;U8-TPzB~hb<>0%s$;?7d3nSRJ9L@zh-m77!5UkAD$5r_fxS?+eJRK@?c8d1Q zuIo$DZbb|rTC+>~!*n6sFyjcP!tIxkA9`Y~#xVrM87IB`0f4Gknck0EJ4(9fob@J+Z!N8S+CC%WXHo^f7E|_F8D})5*1N4JuzM#JKilG4Y5%U3mp^@* z#b@bY-*G$t({n6-E>&G$=POh3^DMsI0Hm?rZq4WTIjqtxgxg#A`4(>&SaFnS;NEOf z#rMiJ`vR=l@ts%{ztG|r(RlB&0>FziehE#XCVqnLXk$Zn1T4f$Eq)nQl+YR_Q2g>8 zE2Ev{KEtcsU$QQc37$u#C)ZL)LucIm$aD@rYuitLj57 zj99|y@`syr$nb6^qbZuLMHhIr;EzxRe^@wr;tG#HO8do{4_gRTr>f-UW8h{O_O9)B z_~T`*Ah;D@`8rDY6Nu~vk#oitUB?e>ET;r!6NUZc2F)Rp?pC91SKU_deu6)>Nqa@O z!k=!IdBsYk9`fi0{24>v8vL5Dec0n9bOObnMLQWz;4kwXRA&6SO<2y{%GyS}{CU7M z65XM)FW`zk;`xg-ln4t2AkQzH(ZivgGA! zO{$`SV_fL3@z*hzs@iGUtG$@NdgGnnV+8I4jc& zph)v~HmKSWp@209+1~}UTmajYd=Fw*UHEgGQ+Rd7-^U&_rQYh#AJCDqKUY^*7vps; zqcHDJPpmX>QZ@L8W+;Z*S+k|zkpcc|{t>Kbgf07Hn%&JtUlaU9-a!*)UfJ6W{FDZL zkADWR@HWPymWBHHCe0LWCIXT7IylnO?m6XOK+Gklxl|SZ(xMA;(fXkhN&a#pLPNdB zzuKTtyak|HjK)v2WOx3L9?2`02t)Z?7+T5dM1_JN|$?nL^Jy zU)+i{^|y@wE)Qd!Ao4%T$R=p{W&`V9gr#b4a4Y_&#s8vVBS5@d{5#|Sq^-sO0gz5# A-~a#s literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.data.processing.ping.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.data.processing.ping.doctree new file mode 100644 index 0000000000000000000000000000000000000000..f97deac68bf19d4b2d82dc8a3d19670c783cb4e8 GIT binary patch literal 10408 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 ZKrPU}@hb;oxJX6+!AD5<;y0KW{a^peW7z-z literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a07ade50823c2afb51c42c6a0c61a71127c7b427 GIT binary patch literal 3634 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 A+W-In literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.execution.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.execution.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d18e0a5682782079b34a3cb77112af5d74a21f30 GIT binary patch literal 620283 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 z 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 sp3e2$LuJN31rxr?&ThFRXL9=`B)du} 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 V;3+pzaK)JRMFvM>@vKdZ{2%q;M34Xg literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.doctree new file mode 100644 index 0000000000000000000000000000000000000000..4acbd6abbc037eceeb6d0e14058ea5e7f5085950 GIT binary patch literal 3838 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.doctree new file mode 100644 index 0000000000000000000000000000000000000000..26c8ded5c0a797c4b4db441d6aab48476724e75c GIT binary patch literal 433963 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

~d33nuT8FmtLIg3CDQ=$jb$WL8? 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

  • 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

    rd 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

    oYPur+%J3_SYFHV54Lw;It`)@V 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 Cg)CJ7 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.ns3.ccn.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.ns3.ccn.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a3194bd8a86d53b94ab5a5a69c155db7e598352d GIT binary patch literal 30797 zcmd5_2YejG)i<^!OS0vPO%J9RWWXxefH9b6$6$;F7#5Bqj+1Vsz4Pf#^X|^J2m_dE z6PoG0L+Cv~I_ad6ge0WLgf!9#0RlPQQki^fHkY*XO?=yLXA4bgtC_3SNUcV-SdH04zg-v{u=8rPR&_10qeqMwk+la> ztz_qOMe4Eht(jD|xT-aqpWWKiljRgiGTCD%1_m;zo5}IAGh$hZK4o7}S_Gu_nmN7rXm&$zld(H+04h-dGLOjS$t?S(D$r zscwXi2CJL7Xz>vrW)9V~Cbs(qteQTM=vkiVv(?zn*pdzKdQq<&bdGqBeR!!k)VMXV zBWe>#)t!OZWvY2iY<>-rDu>34@A%Hx1PC$Fp5Bwo77)k0n$Q_Ls0P{SZs=uUJ3Yx0 zJ7aTe6H&STq|Vr)+Ul2?5b5&^5(PE6_THXbZig+3h&v7pYRa0}fwfr|X+|$RTX)tf zATppm0aH6`?MM*;5qB11=vojR?_iDDtwo68llxq=WtLrU>xirt)X_}7eoV2qgM56BtL zMC+gp$*nXTJ*j&*ldQQl2nct5ulAnKWc-_ge_LAz)*vO)={+$m&eWQ!M|!MReWo)F z|F)^EVavLzCuOgq)zIUlGD&nlwRe}=C%PKv?H=yIO==bv<5sQOuozQfrQ1>4tr1o| zdNlg3>TpI{^=|pTvQV`-xqiDXfv%QlBYPm1Z{ujSVS#VU4>+mpsJIo250D7Bx}lqeJ^)mQVOAX~IUI@;v^tSP!MmUnO1mHnQkNQs9r5&}kW|-G zU)IUa;;4ieOg}}dQ`vNu2H`N>v;H)#POoTvS4fXKqeYfsj+NXRdHtz zn*(sBGf@K2-~}MjA`$4;s)r-6sauC6oIEWUGCSmo8!}&eFG9AdD*F&)N2?UanALYn zfP2iCZA~PTW}}|UChb*CDvjn|u2sg1JB+m&59aj>gXa*{&wX21RhIivu7$faI=1QI z^D#&Gcd3CE%pj?3U&dCdru|%{Nq%~ZY1WyW+Qim~f+A_#t=zW77-4VoS{15z zTXg0);^vAW++5k>sMzrs8DThrt=aSznXsm(veP%FQ_gfIv(c;A=uY3}vW5f7>SD5J`(W6f%(>GCabf#t#k`E7&+5;=d88rlezvxDyzrOLBQ|HC% zz#y)u)tE#fP|DADRtGFo7qnC~EuK$drY{r;)9QsV@*=G+hLN!yDn+ct?%8L0Uon-O ziH>?!xa(a4Z^pCol0>zJ{aVY7qb_wOC#-sRhx5_sq>2TLirG{TFlm#zEH($qH>OF{ zUsq62CZ)7Al7>gGad1|2=fXDX@Uf)R7KsyQM$RpMC0`;bqnU1k}P#Ayu3}T z+r7?oL**&M=)nYn1-ePy0lV(h>Mpixzm1GuzNEX1syVG}<-l!?z)>65;kCiNT?KCjg$pim|g zyN9KIvRrD1^Azv9J_WCN(y@Egr{U&jwEC=P>+^8aALzac^*Kz|tmOr*KF?Z4qc+bI ztmg|=^?VU}JWll`X!^2NU-2}(AetOVwu{|mQ&%pV8EjHtg~}JT`kGeM{23U+R`G< z>_DY`c0m^IxS3Yn9lsAd+XQyDVNcbDrJK`AE4Wn$VQ8tVix?y?a`XQnIy;-_q?sE0hL|{AJ;k?9he}?96K*u=E;Fd1+b2RxcwECsj ze6N_!Rd4jE_2zb5uo={=D6HHiWc0YOwMqR7w!Ws-uRYmVtz`B!)0WGoe#3p_x8)tw zU(nU>qQT%!-$#i7r%C-DI$qc656}@i4UQd=0Q#9XeV(i$^Ukbc1q)+d|9qtE@a{~s z&1>+0w+xNG1?rD%{+}wCzr@=_sXwSIdAslOoTf7R-5Y;>R;3SP$`=1%^GR)1&e ziKw+Dd{J+*GIy8#D!cHH(nu<8W@K=!Oi)(6wN?g*>GA6A&3!T&7=7+uOT9Dn_;W|N z`ls`<)i5wSPv!rj*D3sZu5&8zS(P(B}yt(5`br5^e zYN|(~X$-EgSupSWW`vJ%ouUTNyzy;DIp%&w%G4-zn*w!RC@*-K#tI<-<7ph1$T_fS zj#Sy4xt-E{{DBX^o2 zvIG9PNYpoGYp$?(({xXT3^da;B$~DnjqPdIAa+q&hA|m!D=ga?7H&z;VBk+dWVF4| zs$oysLC7jL4^zyr8>WOg`IvuWn-|!Pc7z!fFemMVa!nr+Bc-Q${&|R#b{1My|E3FB z#ZH2O9_}og)Q5*Z!%M|XXB<1Q3-pBXrvs!(yP{arZem24{R}o~ccGoL)~Nz7odBw& z8DMtKPjeF3Fwq_&1E7)iL{3wS+_%Se8_MY*giN!YW?gm|D$-1ma8MWR#e{JQ=cCSL zv5t-DBeXXppfm4-MAIx>Ly(YKT?Ol6+YMzcwJ{&?pc4Xu)Q;j72T+eXkkhoU+=l^Q znxo=+#}JQZ3sc!3_D~+pVg4Y{qy10Vy2nv=Df;RskqbA^7Op~v>!n0Nu% z1?^=xNApBrb$bs29rkXVJ~|k+;oE#9nhp_F#y9rH_y!0^hYI~LLr+U{ge+wYM~4f! zx}`^e4oin_>IGneK?{*+`mjhe2C)goARsqdB=jQ#^guf^T%)6eR^6J#LI+%;qea#d zBdY|>=$MKUI?}A0*XgC4dKis5aRRGtVrRC;iYEZjrsNk}xEER{{PScR{Ymv4YHiV52(0X7pfpf!ha8lB1{1J#@% zKpLF}KHj9#=_0Yqmk1eWhzt*sIX)1>Car|8oZ6ukFHXaOR^b`i#Z}T}0j<&;0&crF zr$AD4CNi25Y_x2L;6bciFR1+2$3$a<6b z5Xu2aB1bBu0u=(YGUFpk3oY6;e27HLL3e5QVel-i!y$`SeI!(`;uL&zysj z5S~eMoAFRNm(#_YC1P|QWTDrrMxyC_T)iR2*2~yRH<+B9P=pc81ybw6QZ4VtNP}Q5 z5<;LG)5TmOk7^8KiyNMU=n}|qW(tH^!`Z2_+uhcKFl$9ALzqjE)AUifZ{M`%L+CQr z)RAU~-7YN{=5i4p@X*CDzBN~Hg~gkw{7MKx8(oD&(>hVvo^~x_C(%q8)eK^;7M5!a zi+~u{Vjsj@E3~Sc{Og3QYW)Q;@@PQ`#qi@i8{Nc=0!4!ms?S+={C_FwOX*t?Lw*% zyW9b0U>8n;*yT=)ww<)5mZPLzV|z4eR8&xk!7^gG?<4Di5L90F{T4)AWekM}P{4z;#N1%A>+m zHd1|{@)+}nfXd@2f$2{m(e$KLH%-S{&5&cD@|4h@HuTu+@>L9H#~XaC6jMvUU_mO+ zh{Wm!e;jleypam&SyYF2&mqzDyy!CCu|LK;hAN*B`X>!NEe#SfRiMhJgk0U!PlFCq z`O(N|6MqIInDJR8nm#9Tj2W!hn85($1)+aFKo5jV0LmAHR^5g#3Y`JUmqgZ=jjRAb z`AS6z9ck9htL|4h^#RI@xP#$eL!#;HxO(d*i-+L>fbtFD`KICV(FV^|-;%PZ(Iu7N z1|2GWfbtUVq4YaQG<{bpn`p5LU#SOBz9(!i2iQ!|e1P(OCe;8?egHlJC_fa5ulN$- z!jDA8<^w4F=*h4EN_fKY5DNEHMkpKuZoD6J$_V8r$Y}a0uBO4@!q4PJT7iDfd=Z4g zUbBo}a2i1#d4jHuHn+6@bj&*`6AJjLgyR)qH{#9zOIY zwD?HoAFPs*%v;E4dK*`C@3aI6Eiyzas(b9sQyeAZ6#!LJnsHg$n=&7 zpsi&q5LqFo`_HG&bn1DBITCs*>@Y{6Skq`R!mJ4;^JRxwC!`^Fn2nfweRWii3fN_G z65M5u5jnieY(P#^qujU0wkcoTy}yp3Ch%ZLv5mov=2)qUjpjHe)Nj&8vl$}L~@Co$JGW}6c}9G?tIi^DsjDadKsTJFtc<+e5)e#XJon?+d95NrEhQep2vg+RxbwS6Cc;o+UC{OESYJ zEp1VO)XpXHmngNv@bW+3pbm&}c9p}HeL34Gn0&f-*fLx6@?pyy8W#WmVLaydk3RZk=i6|#yQf(f*S^`g9yN~bRT2ZEc@+`PUV26HMMyc~{l zO-G2aW=3-T^nX8IAhfD}E)=qgolv$=@LxO*@9?EO2s52AZ2gC!q{8aB2*sL?6bs6X zm*w#&p$)k_`i~^jVlZQA9xXC>XXgW=*n?_`Su3oe2r>F@XfXnTa~%BYS0hLSG)B2ZAO?G8v&&H=|$Zd?b?@eS8u&$@i07aBvTZg6^6$@U*RK}l~NWpx}NREGO2@7y>H+3U&^p2x6X?s?1& z!giy}w#Ck4Zh`_h$co*qpq$6t%z8h-^O#%Mo*K?$WR8BX);|*|A3Jm_6!}Lox3N|} zlDQojO?TjmzMYmBVd&o}_h!)C#d&ii!?uQxWbQ^u_(+CZlgHCNoNoRjnR_7?UF$w1 zn(oKd8SkFNq9BKVL>p(^uraBKm>-A@surx)4Er zf&Qvg1^RiB2~&oLe#(MFUxO5M=dUBt^bK6Y=;xcRl8WdD(&$^vP>z1Sjbej-UP4aO zcjP{TemEAcYl42hD@q0nD3^qP@K zS+E%W1Z)=c^CJ;j-R2*I4x4L5Kjk{GtzQKdmi!8drq@K2v4nLSOBnt9TIjzC&;vme^z&PxRX5{z zLTB{zdy)0JkrhLNKT>2U@&_r2O6W+lZeFSX$f=Kh{)9Ui{%0hb{(`Hwz_NH49zZ{T z6`sEt9v{lE$~UB}y2`(U4wXLoc@y_g`VSY<;vh3%aHn+ckae*Vd% z8qm+X;1l%oo=E(cFA*;MTV#BI=%=iEd+3MzE2AF{1GnFQIA!$nJ~EpAi>qlfcrjuW z-$+ByR>()u4?E5>Mlvmeenz1TjWQaEraD}`p1^ucqpUYc82!{sg)xB&fq7ZbPlM2+ z-J^tl8bKHI(D-L0UYpRHN%2Z(;AvOP7RADN?TM?Ym_ho(W1kAAjct&D!Q zMFu~Q;flVUmKb5sY%lj_(Col@gMQf7F#6dMC1Lc#t;yqQCr&p%`uPyVqHFDp1V5|c z>J3SDM8@I}=w}zHwQH$X82#)fgg{@X-MM6#PuWJ^F-0>V!)X!dvj=ClmR)hX2YvPw zr3`&qki*Yoa$oaPwh?U}?%9hqb)?y0x3dfG*;|AMJalo7Z_Pejq2{M-t0s%-xDCcmg2b6OJ6Pkzh z_(LQtv;ZQ|c^4wVA9~>$hB%8{4V9j=T}DSTwH)6Zg<^wm79*$WXt|Hz8xDc%l;E2s z!c;a^eSC8a^M~-wQk1~-P9&O+mFlMLSgRRyjBkz;`tgQd>tnBxFfq6Z7%bpsnMkZ| z@Cl&9;2NK^jVh!QQ61h{NbviZ=rZ21KgK&oHYW=`X6R{YkdUc@Y)%n!byH6T9j2B) zXS<9}0|{oFjzm+J$T4QHVq*rwnlpqR56}bQ5?FJl(5l;z5IVz}ZjsevWCdVNvZ92J zH0$Oi*yhxSHNCil;eALnIk^y-C8D<~*seI#3}n3k#+>Uue<3QNlDAfG(KkLJ@V55%oX7G;BI%Rv*(` zESk#%%}>}y1`b^XEk2-G$0`}nT#byTYj8!!PD_9=Vy=~YGh(jeya6<9 zXc*93kCHH;;ilxlbOWcGAJE(gvFKMfA<=X*uHJZLM`R!l0cdWKTDO*Jg#pcNLI`wp zx}8hpwNN!a-BkIVz;p-XIJ*m|xs$WwW$!!J12uPvVg@yLBd6&exo@xOMUs^@dcfvh z*4B|`$K4(;z~(+t5b)FmHoisobA`p5!GMoJ5ZdbjB$^%+we4xwDs~o4=7O7tgymtw zBH+fg+6Om}2(9YY|4|{U*r7E%fKw%EKEUBuvTst8Ggx>G22}z%kE2}E6JoAe-d#_9 zkn^O_s(SjAkX6irm4U~$y_e$;1L#za!%U}%?SC3-DuA75P>f&a#D+5S1?)U4v>L(A zb6^J8;Uoxlo);Mmc0PferccU!du*r5K8FAgTj*i~0X(0Qx&S<%W~z?BU>)>b)O41NMe3;6k_ zNUd)4w?K!{o1m1w4H5A2B_#NXO!OHq*)QWI1EB8;{dv0FeUqzznSGansEsKZY0TA?>@ci2F_=tu<&~KzHYII5EZ$XDj z9|Zjl_fYzKB${5A$|hQ@!dL2npg#!P9|LSAXg&z~6O(EHL4O9HfS|vK#J~Cy;lkfU z#^wV-yhPRfWLxD?!qWz-;g#H7%0HOCq z)PIerEe(Wd1Ue+*%JyTr_0iB)C?4u1ku*{m!f0p|$`HKKNbt*;FhtQ1JLjUIdSM&m zvTZRm)Bpu=kQKXoLqS80toH*%LrrW}4QNQF>i25;@xSs2qOs8ABcgGvmJv}iGMdKY ziXNVpAYtfCkb5(9CUV{&A~rURh$f*VjEJ~7c~nj2bn_#kDG-akwKWn=Q*reMCOaY{ zatK5;O=@jZsue~=+X^8tG-*37iS35@tA_0{Z4Yi|hTxtZI6FbM!-spgXGamwxMwHi z@RC5eZ?63}M;Bun0DB?eMY5oC*}wH zyK|YiS1V6#DDI+mCgM$=fe-wMybhu6%hatSRpY`iTNvgrLnGeCEN^?y(|%IAKd#(C zta0AAh49y_HXVRsd`-yr#s3fy&6R2g;>y+!bc~cX7jmr8GjS;ktm98# z3{ofOn=^@QUlAXLLdB#_$8y<7J4?rLrZJhoCvFOf{sB53_iVqkQ9NU>urss_W%yjp zICzSWPT}JT_+$^AAdF2;B2#eLPGq(^tJ$^Bd>aQZB8Na{QKz*dT0BQ_xRR5XjGJ30 zkxgchJqc{qM0OyLiVpN=5DYq*i|dkhcd?In_t|MpwEMel?lFV-@SS7Z1v&-gYptE| zrJsRfp_=?tSx`Nj)>EL<_@_7BAU9-OBxlw&aB{pP7` zZ_Z^t!!VEMw>9$%(;?SR^iy1Tr*gCPrZUp_@q*nCSJ2(h1Q9P!wg+a-XrGg$1m8}w zSEcY>E)1?>-i=~6i>|Zk@y71nR3G(-NNIC)?iHzgs*oc}O6k;|OfIoJZsRrTnK(Y2 zf)}CVecWV&xW?KEuJ-%0L8%+X^Z1aKO}$`RYmKtAE2vL|8OI0mb}} zR$Z~sJ8LdwIp5@p;z5)%l2X}VBhvu0HAhrEpOeA=1v-a|M`v=` zK024PJBFhd4-difz>=1sfuqktE?x@PYOXvom8A1IGah3h*z6aeaILk28TNL@mT3uL zEjV#``8GVe5G)u(ZhOe!$kRnA?6RiGNJ(Y$Hp$2A>@2rjk}d{y4PMKaScxHRiY`GB zuMZMRe@h8#MELQZ<%IZ_!LjO+OLKX`~V%IlDK;v3XAPTqf; zZpKS3JU!Qoo*PPfyw^YnRoxg+brbR;VME%|9f+}~=4MfIOF+#meqwQ7C#dGufSTJ_ z4NKUN8fT_?3*WBhkHeeI5Bg)wpKR`Fys0;DVwjBY(@c@4nbUmo@7Z>{*mg(2Huu~& zXxp6u+wNl9Si**EOY^%4JvDcWntK9j%$w>$A-Ff7<~~-#5;mm9nIZe{^!8lA?LYS; zk2kD|IMaKlAs-3&141^v_Ce%D!UnZ9$+2O2Mj(U_p|YljMV!&L3#buoj|8+m%Gy}M z2DR-5=(D^0Qc|=gWA!P01Jmq>9~0G&};(=$7>yZ0vF?>mlkO?OpSSKCwFBfW?AtgCOXYirFm|ss$QT&(BHnug?wq~1~hV9Js36n=n4w6*5vAH!}lW(q@k#2SRw5K*Kp{}kW z3yXYJV{~*nGWTsyZCfI9aa&+)jY_vPJN?>I+Z59@t-h_krM0c8Dc#^1k{>m$zPi3; zcb%r%nrbr5jcI3*_SB}u6qRZor=mSo0R{QCsg2F`Z4GGjMJN1^O_WCy^>0sYT*99C z_RY7}s#a$}dum9r>}ZnK+Lmec=>Hj&+F)m~38~GB#r_TnngiY?iu>GgH# z+Lo4vY@IdO#@3~G1OHm`3qxs}V0bwzw5N8SpB6WbV>kGU?Wskf z6SKXgwr)o4bWHb^Cd@a$wlvhD`C4jQGkIs_5?0$YSVJ2iZTH%iarMCN8U8FF8o=nGZ?elgw)^?ne?bI8CIW=8e1YmaaTc; zGwFtwv~ns-U~2Iub=GK4ZBopX5;NCXvpqF#KJpKP=d4LL)weWfn_BbES|xC@gf+uv z)n;338k*~B8){mb;W5^3PmL*NUFosWTvMM0_RetzmS`xbil6$~rkTw%(#|^V#b;8f zszp4&p!U?_sG0V1l>qWqEKBlE)r9#2;?}fk%r*fuZCn`Kp4z%tD;6JO!|I!BwEteW zeSU|1GhnzOU7Jrk>$Rsw7qcm`JMtK9HI4b{&XD%hdc`zY9b)F~&I!X$@`p zj5D%5wPmr!F4ZjDLyUArEdVVeoDJGjTg{Ixa4*?ubDRxJEZa&|NvpA^=0@{7cFe-d z*|>zJl4IMS=9{#qCeBY|)n(FkGYA=B6xy^z_{@tH~K(!abI#9FT!nwR4H- z0Z@ov8wUg4+2wy-U)QNLH~ACVQzME^(Igw3i6wk{i6+2GN7`W55^72Uqc}Wgw-TeR z)EvMqD1Gm5()`+kB`WZKa{Gc=^2!dt-?Q&Nzk7Cl!?uPugPrQqJ&&1V-J3JWwa0{1 zWsxCM>D>i!_MG4Cdb$aBx6(DR!b!EaRWFG@&sLw|cRxaKZ@K=GqMXM{Ud%IIJ{qZ*de~VQQ;XU=C{yp`f za!-9I2JujPJ`DBlveso5$KMk8TM~au;csdDErY*h@wXiQmdD=;_*)TwD^)LQ-(#xJ ztc<@^@V6@dR;wPGSafI(nX=QF)vE^=%c7yjh)>H@;%^Q7t%<+2@V7Sp2I6lW{0+ii zRrTV!T0{M9_4LeO{H=?>_3$?Ye?zO+ODxlxqo&kMW*Gj4<8OWZjlkbX{Efoj2Kd_$ ze;eU%WBhG`zfJKs8h@MNZ*%-@fxj*Bw-x@j#@{yh+ZKOg@HZBJ+f{FvXbjq{(03cN zvYB!C+a7;A;BQC#?S#Ma_}dwOyWnpE{wCsYSN!dUze)I;jKAISSB<|tsz($nIy~`A zvAN8i)s>0a%(R=4No7)P)&1%+SS?}-I1N*r#^^JmyuN>3;WXh9QM2o`;1Q9kouzM- zJ5F_v>OPoNm_Lrn^sMgVrRU|Q)o?x}8IC*QO|`@M;3YqtHVwyPr{VdQOtxwE@S29& zIn8aYk{#)&1(*S}2!y z=1i&XTh~yV&*S=lDb@X^;)bgt5F9wAdSTAlgQhrcW=3swZ!LfD6z7o4p0#b&yX3#c=S4A5K7}JohaE?IJ9O*hoRb`y=0PpCG$~0&4nbu5Ob#GDP z9Fsv6+N&~ireqG7k~wfn=AbE=gQv7*U`fU+e{Qt+-Ep6z!s#fl%wvx_%sI|=j)##M zmVad1)Y`VG8FuRlu5%)it9t}yWoFWzlS1}5CuizwVU%-9W~EwM*4tQiYE_19aGL9! z&Nkpp?#b3o?lYkG1YO;X)bq@cUay|MwzD!F1uD*l_2;r z(}Q*KzjgmVQ8y%GbpsjYEpTBYlqtH$@J9*}LS zYiO%aXR`J6n1)x+%_!;9QnSOkrn*8#PrkXSVUBa{-0EJ_8=9v&*UjbV!5Gqm>0rzS zOi-1@T)2LUbHjwx+UTHC%7@j}H90pP?c7vb-N!TR=DF4VJyW@#$UC=8ac<4rSX+r?sc8}phljXVvuQ1l6UUMpt#*0V-JM1dSlGj^&rL=pS)Tc9>NfN*mWL(@(i`z zE7qGi@~G=P7Hj?Ep>mujs^qSx=irEUvAAZrFz3lkCe3N}RA#7DcyUwVr}eaY#&w=$ zjk|g`^*L1HQM*Z=51HyUiC@|aXp*iL@gmynCD(bGZN}oB(bFDd*|E0`Xy zy3T8+9bsJcBAat{1*qN9d7Wq|qRtzfCvR3I4dW@!TUGEic=C%~ZD;W(N>)o(R_SgT z+|@3s?$PSJEq$|)*Ebl`tj#;F^R88!37NKxnEqZ7)8DVkbjnkco#l0j(5nTNRpPWN zvrXc@OAVdDnKfzJe`(qT-?9RH!n+=I70w5+_e0nDC~R+aFLIra+2Eg4VNHt%Md&Q& z)4A1s>YE#DvrW!tsh*fAEprNbqj_qMZ;Cjdr+Py`EO)+u--JR*|1$H1Wtj6-Rjg$- z`7E4!D{hKcIA6oYZ(QeF*qB-sI%ArsDqT0Ea(Y{~elW({hv5k;zhDmh>N>wowGr3(on`f#*4EG< z3zvDRrQ@sP{88Oox7?ptOZA?X<%;L8xpuq#ozQNzP1umgE~Ucx2MzbHt9mTdqX*lr zkLiy}G}1S~0JhBH(lS9VwGgDyI;yASDp+}#5v3NUT!*Dp^+L)~hpFBmuIeM%_4480 zcmU8P!(U=?R-yVL!{EbIKgqp_&Yc<6G_g91ipJ#X^ru`$`30&0 z$bi}|2I8v4MZ45C#~Ku=u&(VA5JGL2l-x_{+?hYDS}Y>9ps-pRY*t|z5lgPZvXtvc z8dGXHuwn4>Ag)?LbZLWWL=l6rl7|&|Mu}HNS}W9wkcQH4N!xGlk?1|lAMEe&QvdqSOO6ZSy$4M4OtI-7-F)hA&A42 zp&+grCYf~)u?R6Gr;Enwsi2X#+N)5*A&I70UsQ|;RIqp8h^l*0OpOGC29BaYb+7d7 z7FFFV)7sdeHXtXwPP9-*Z3uQj$t}1A46j==8+)k=wGl*M!Nwr2+619)Pn5PPBh`H& zMMqHGZ)P?TzgHhcF>G1fOYp|8%6}?RL!ui&EwHesjrs_q(g0*`$R^Wm2NukMY^=&wK8GAhS*;}F>#H0lbnO~?i zu}H&c*bc;1;}DvG$&&TJ?4xZ`+xsc~?aoj;==8R!aRWxCsduxbLhT4q)M_UXSB*#L zl}2wWjzYt#C$Dyf1V_*=A{iax{<=d=AV1oYoJrHMp~_UKiQuEyT|r#6n<#TqTc8=X z#rp>N(Uqgc4UXPF)(J#j$n@XE+#fy3iiFkyY7$f0su%G~SCg57O6)G>7F1%qS=Xs* z5$H(u4GdFzAPwEKCy1+3BH-8puz|H|o0{`x#9kt~w{{FYhsePcr)2n97(g(o8fAIN?udl zuVs#I09DI`KhQICM(dfYrqU{INMrjQGkBOagH;`*fl}l9aVpg#5*=_2S-7v-h6-FX8)n`!U}`Ce-mJe zY87^;yy0jbXjBcZtSYAq;$D%d#G)b7j1~DLY)4cZw1;;j8SFjOOeDK%mK3dhU0^h~ zA8NL+KAoFM*l=V%mnEn!OU;3F=F1$3?Y0gOCD=!(199c5gCy>x*1-si*-Z@dt8X4| zVq1};sTvD2+&(B*lpHig9Zbfg+RRUx@;3|_&81m7&dP7;MDYlTuh z({b#mQ(`r#9L?Z#J(W~f#$;2cAq|x|9mG{MH;&2G7wi?j?i=ui_+cW zuZhGv%J{=7DCeznu8^EpS~-L1oimG@tAw361Ow>3TC`nbX$w${w|>;M!b*hR>xA8z z+8Yxy{za?>0>qmVh_6RkF+h9+l3jJ97!nJ_Hwmj;Aif#W0Admwh;I=k1mat9<*M5x z?#LG=aX_5Z7#L_Y*oNcVMHS%q4l*|FA{^g|Oc+pifw<~!gkd3Kf&;ZpT&(e{p|ErOTt3M&yW-xGGHyd+~>_K5jd zsrt{12WN&8Bj1Pq7>xWcl3n$I6dsF_9}24|MlQm&mw803K0*e-B#8}^AB!HsR-C-wz_1IONoi%+e9oq<%soD)lpnt9}s;x;t6C z2E5_8Li7JBBEMN8+6EhOXzefT+JjQ@4RAb{HXwjX+@e8`MD5 zKe%?)zX*MZ>VXGB-m^rt5Uyh&igl)@o?u5IYGI_IQ+k28sy9LdQ7oz)i0UIb`&v1J zso+CYKVc`1mtaY^h-j;@v_&9lQDG%QRDWTIA!_7;fvD{XQ3Ieq2BH>2G9E`r;js|4 zgs{2*QA;8NAd19>sHH>?A!=z{;o*eDOGDI13@93DL)5a87Z9}^8QXUeqLxP{44f4} zT(u&?Fhs57=`0OVBh|{3Erh65knBU$s))F1H6}$MidAD{L?CK)5ltL&s*+j45H(V* zfkaelO%PYDB^q>hviJ~0tt}!0EfH;l4N>cmTOLFWf~bM0Dp5VyR}F|-S2T4Sh+>Bk zqSy!omi0glL=C~UtA--8?wfTDnQm)GB)cXWNn8`7)awlT(v#IFl6oE>718Z6LpN+7aP;GrD{iJD8#Lu zknH2uctl*aGn0T@ixu=aD#=!gfY&Y}pEwxR1ZL@oQKu$?gF5aCf+stoM)x!g(FnF8 zJUcpPl88*UL@Yzhu5x!_CmT`?zPTN^hbY`rD=fGj$OjgM?>wm-&EU-6i!^dOaBrlc zGW&qwDGNd~^I4Rh`GfQ_CD`6h5#jwTVO=d7m}|%_5199dr~&3$Q9adH4PdSlP2C2V zIU)(nYy>uHJ*WZZG_GAW4WSRr(VT$la(`=@IEj%3p;TL2Eg1R+8j$;1eleu5`j4{?9S9~_9W%^E(-*gHzzK)qKFt= zZbP!GW=i?7xI9Z(<>K;eNCTHiY+RlrN{Gt`;L248N?gCoSQPD~4Gi`XmT9jI%Lj=j zz_Lrm=3Rv4gOLft=nxQB9f~jv%ZGV7=cU#t1RuTAU zd=|OoVe;7!HJE&ks6N+M4NN{yG<6$H=6EC~vk};+=Ytwdz5v&*x)7m{$^Vgv#^j4A zT8PQ4Gc{dI8o}gCkcRHL6vS1RAvE2?qRPSK%O&R(R?c9y`hwyP~| z5lp^DSc#Z?t*|@gpb!7xqy>V<8xxPOgZdaez8=Z0xkAfjYvkEpu-zLfd(YKSaaTg)_ z4rIcpx)a1zcOeWz^xdA$BAb0h)O*S;;KhPgYIk=AA;paMdUF{#InJ_^5eozw&4l#4K6<^8lTb{ z3vl`ASXC-VJ2>&5A&ubjvq(d2o&&*C7ldZwvnU&vjR`M^!YF zScyLBCt-J{Qd~wFbg>SuSs?Ce8M>>VQBsV%`UT0Z`c=$`byvR$t6X>WJEY;RNNjgC zPn6JI{edf2{V8!LwIixs)Lq$45jd&{Tnwo+o{P1yJ=b4S4m{W2WGvG~&-D*7VXXZN zf=@CQj(V|g-&c?B>PUR7b1A1!X!AcWfBGlCLNnI;?Md>uEepc z`ht&Hm84Yl10S_s1jJPpqD&7A8ig4K*z@iJEh-}YEfLEcz=$mW)-Ua|tBT}mTGIDZv|@EhOSYmCd|2VTwlxq((QAU> z358_VMY9OIXv?*&Ey4pWVco~JYg>oh@?6^>h#J>cC8`Jes!^kLMN_wNZJes|tOAq+ zY&}rp+J@j7&ngi5u5Fk^q(9VfiWa&y)|r~tCylta5lBP#j0C~63WR2;vMAj>#a-J5 zl5;~VXMl&kYuiZJ(LodA+BOz#n^@YkYfGI0I7&DY0H^Mh^##W;yf=<7NAmcXxoLW3 z^R%+Ql8k#}Ieadr+7#A$-)^eWVtJzH-Avf}j$P<*%?09e*P_ea97V*q+%1sosx75_ z+vVmw>*Xctt%O~!+ua({aJwY7+ucT#(Cu!ED_4z?xRY8d!Cyt%0se)y+75NBXn;fA zj*PXs=upQY6Gr&r72kNh2s-hct9?J&3E)2n|ZJsB%zxn&g~r>&2`CYE(k_VBwpQYhmrApehD5Un;jAJY zlCK(|0}V+FGkFh=a+6UCR~wB|K!HiYCs$3()-hiOG(!a%w*|yijuhzRJgZnunL?OF zSfI#TiAn_XT9D_Scps5r+{*|2s#REtPM}TL`U4ts()R+v|7D5)God{O|7Rf?U&%<( zHvZFS!TveIDi`|?fHbh5#K!&uMG3M0AY9?w7l}KmYy$TC)i;A9<^~~7O2Ma@`5~2c z*_KRN8Co+VJ!eSe)L9ML#%$}5%GTLVTe=PB4>$2FG$+C{Qp zium8)%w-mhCq|L#KpJXvEQqU)69sxuu<($}I9^0futY2qjLSGt*vTfGM84VUoGcno z(HaZ3Tc^gVQaRc|bUckTvfVlzX{gN^Ag($Sp+QF$rO{D8bvGuQC6Z@r$+!&@q30Z7 zM=KRraxVC=ByPKP9#}Bwd=OV%AbNE3vfwy_E)>cCXi51x)Eo6QV38kOTuR1;IlV$*&DyL2(9LE|OPhNqty@%r=&PrKBd8e--#BUyhBCOzLW+p!jP* z@J)+k*Tu7#xZNQD^>g1G7-QK8LXakd%O7W`ome#8>i^WI+EJxXqQi@V1l zY8H2oi|QwQ)u`8#qN&>~?g-Od+_4b|I!}R`#og1mcGWWo{l(q05|Lg}&r!5+amPAS z)AOW}#oY@?L-)K0g69_q4ScaE-95#(;4e$gSFD_Y|MM4juL?UlbYiyPuZgzTEp3sz z%WnuPae4Emusc(GTAs_kqq-nI6<(1mowra>%u1&d$*y`^tkA?+B~hmCn16 z#!838Ug^9iO1RQ_A6KsWuf(0ywy1U7&1K_y?UqPf^l%BoYS>Gd52OGrVLl{d#V#&k zK0+ppv5!Gq^$Ei866RA+=e*RQ^6gijF<0Sg=5r+btC=qlan+Yh!fJ-+7{#;%s>@c4 zENs4#Oo<~_ea$TT9Ge)O>Km|8D%`iSbjzG_sipJ?hfPKC3DPKAxYUS0&$IF$-q&dEG0RYwsHoDU16R7zCgCkJJ6Y|hyr4q$x29e)yh(OtTS0fSmipCRUr*$LSj3U z)kF!M$?CXrRi(roIoTx6nb<9WU(2DpprN+ASVL66U93sQ4qbE?YatUx&)Oia8i+9L zF4pmM&P%PH;4Ul+)gVe2x``?z`)*<|B6t$RB)AEl0c&YM_1G>E_pqJ_CyqTegjw`q zu$C@06v?RCFc4P_7ah7|X+p>?tS=%XED_5J;}%8=JK2g+;2TKZKooAM6{Y|OJEpb&MK%-R%`IVF85?@HAh$f| z-4db(dbbkQTl=a}p>0G{w}D=cKteAYf$h01sDa)wxOUZ8gg*3cClL+3<0x7Py{t1e zZBH73-W`yJ?%5H(6B_GgsA2K%RBHHeYOc*dzKwPyS!Z6y_csl15 zH%skLxk8++MY4~xQxU;OAWQ3E!BGQ54IDL!>Ly<`;HX(NbsIQhM-h(L2n3N9Pyr72;q!Bopi8OS|ED$^ZKxp8IMU?|bb0p^hR?cAf`*3ui zuoK5h07nOjHrLV?funD8kX9&>aIuhanj^{-xkpI66XDU4Ww_ zkpXZ-V#CoFxk5NP5y?IrorH+1PG*t?N30SXAOc6Hh*;tfQ>QXZ07oO$X-GgtP6xr^ zT#{RNABzpa(U~H0mL;Ogx8dk)a?69Gb0BKq=v+~Kp065kbiQcnHgLp_A{?<12qG7N z8aTQT*Eo_3p$|tFNkqfZ#S|@sBi5OkE+LJ;(WOX3r(6btBe@V7IAT%dz|j?w^GYjc zF#LTux=PrIVQo$~XsE!hQgaKqxnqU)hJ28(V$GS1(U zQe&~`CSi2}i*7~+U=fLpMYo6^V$rR*!Vz2&*XK^f?MYj*7(%qp2BO;~6M*OrG8XS5 z5Z#GP7%F#x;PDB6|BrR>j+-?xj#63f+ffABFBm1P5y|2`Ge@TYE@lSnmh~ zJt#7X!%98GEc(dkmaKXhG1&hI2oB7Wth&osU7-Xd(Wv&eZf0X#{^> zMjATh6%bdwiqPN>iz)|yUXz@!TRDSK@8i!K!cH700sg!x+TOCXMewInSc&-awy^cf zB=`ja`FXhoa#w5-g3vqA9s@$}BH2~%Nzt(&^uDl)f{=AA!+#+S1R}8!=mSwg1o{wH z_yk4b$)~aU)i=*ocwdaB+KBYAC;=jULdGIpM5IrV34`Y|5LbPUFpNlFcsi5c1Ti+M zFDY7xOJ5<`$EB|kan(0W0xt1Q5R)AhW1B?K>06OZ9CYeCX3^8ZC{o`e4K?}!#8p3v z0^Or5Tw|2?;{8t|^0OsknP6^*{UYpS6MhBX+z$Iq6#lLi7Ca=G7pqC-Xa?u@AEdf6 zroYvnNJC}*0>QHlgl2BDC_T6Jiy+pGv42GPUrSh5%ZA<_*eI6?y$eCqKyOc6yJ}%( zHh1-ViKcD?y&Q#vUN!<7wKuKzPGjvO*7voo?YN{ZOK<}bRL-+It zan%5Xrh8aaIncY9|- zYD~gCve>3DQ?%gyK4LWMVPo{FQUWk~H8KWw5u;Z}CXBL55d7)~!Z1d!>FG@VfGVy6 zYAt3f#Ot+@?Bn%7MDW`nOafl>TceN5-mBIod&_7)2TZ@(qxN z+H44dry~drQm`l+$c+gbi{vI+GVXabAG2&K>}aI|OGbkaOX8k(Zw3|&+8hMuQHdVi zye!x@$a>nnr3i0j3G0ToJvy4X?x@Tt)e0PD+j29MFj%S%5IVV~< z15olk%dWzXj-QyP-MfjlNtU*VXPGRlM9;Fju=R;+Z7mJWwe{W)4Cfb!PZ>m?QjIcV ze99h3cGaF@K&(&U?f$AvxjtntNW-U)*gj=%Q9_@x53cZWhs2XlT#Gb<@g{U0G}v|? zQ$!V<$9`lC>Z0?gK_(2O{Xtw+i!kgwrg}P)Ph1OIs_K}b&~4Ns*>@XhL~za(li)UZ z;#ybRWu1Z z*^p-N4NSL)LPsks@DwUmlgiNy&ip)S#8b2)4V7sF!GTl=&CF*}HZWUD{#hbC+Y;8* zvVnOHx#a=#0T4C7e4wa4$X5+uc12US0cMU!0y7(dje0Ps0p>$+jT5a9`oMgcL^LoT zPSHYOW}T_&2+{~JABi+{&ru-wT@i$)dstLCzZ$R`V{TtGer(g0)< z8<0;GB?RQtaD{WSB%b^Rl2>^fh-s(|#Ak>K0P&e*Y}iF0J`0&JaLxw7rx*ysKzy#J zb6#qtgl&knP@PA?LI6G=$vyyIfCvt?ViEwDH>PxE%o4Un1bF`=a*2aYUBoQuTA6do#J^0q!jjHGq4osJ_it4Zyu! zG<6%mW9_(DVU=;md?wn5fSmG4FP z2TNEtwCzfMB)2?Q@)JajEBRSe|Kh7g<$e`S-Nu!0rqGqJ5!lPWff`rxJFZF|B<`d} zB>0G+4Fb=`Hs#Np^PUeaw_Vy2q7N=@NixQD(WNbgOc>`&gW&f`5QbgavYyW5vqF7y z)pC?AbY;sU*>`0tAc7wtVG>*!UsLw;qiSrRhznauL=$I-TA5k&S)slrwF(kZsZ~Mn zD%L6*VY;fT-U%@RrtgM>4c(nNF%Om z5YkYaDiButIQ?$@ovCh=A1!=@tZHY8=&sHF=+8Uu5AuOsKXSI#w z+}6q&pp5UV#t1t)aC~Q_#)5B7$k|R5j?)TLgE7zdgm1`Kwl%e88!9=jDw~`9Q*kP@ z`O4|(Cj9(#Yr0--k6dUv+JrN4G#>kB;_M(Q3ycWP#MzPAI=WcoPRN7?91nt@|Bxb_ zoM#8CBA9`js2JXI3eGMfI6(_qr{JW{>UQq9p}DTMp+*kcod|o4Q{GiOO07fhbxn|FPan04jF4r~h0cp5q65BQJDN5*?dE*OT zz)0MYA0>}_rBXbM)e^=*(=F3#+b!=cy5N@gA!F?>y5)V52?KHp2)>Fz77T)qW){5(is)0* zz(O^rgW#JP(W85urpTl-C!c0TBxi|OmKaApL)gidG=OiMWTPl-(h3XwbaSjGe6@mf zqHqgo#7{d&LuC|*tMUj93bQENNm@^1T1B|c64uqSo#ae%%X5;mAZncCY*9VOR}D9F zfN1JAPLgAiPLhqlMm-SJILU)>jmJj_eJ6RaM5K4sArviilB_c|9ZDK;l7}G;-E%mI ztBycux`#!T<0OxioJUzXgE{Xz$)kmxJOqyc-#E#3Q8-sCOzngDW;;naO3nvw?K7t} zD>*&R08hwq4ymlDZK}tQ3(mFhq_Xl&L3ZdGHc?^cf$BMQt8-0E@6 z*75(`$m3BAI_U%uSDh$EIXTaAHdoXUpCp1OYeCx)pN7`#Ui)I4fX~Ghehfz9j;!7iy_(kwW)9H#(qh~Bo-cafd@mqli!M6f3y}$f@IN3pfDB>S z`CjblOg;d>>MV5$r3)SJrAYQ2?`4SKdmtvk@$vuwO9QIM#)&xHD@3?p!un44N@mdq z09d-zRY*qFt_E?{HKIfJFii+K+-pVTI!nZ|!Z_UPg`I504d5Gxd!s14Nh>UHxHrdY zQaPGIM8AbJ;&5+88Y*)e2p)VPG>Fck5*+RwB7CPMtgB@^+`Gsv&*9z;QR8s$5!Ltl zs^M_&6HVR5;c_g};j$6fsP}^!hx-7oUG*SB-{C$a5$Rp^FhvU;F6&H9kB~+j?xRRU z_dEvTs>czU?qN~oINT>B=aW{>V4nL9_bFi~55cFwHxBn1QTVJ@D8JmZr?o4k!`05S zvJRiRm*H{Mb5Mo$q@nPs8XkS0`n;4=U|HZ(UtqS51!2dF(1fOb3B*+|OSw+YGme$E z+$OfL`u|K5VD}Zt@v6>2|Cwn9(6quq&E&nJ*MwnJLA}lt!RN;2`nHDj(57@tb{HVJ zxlPrj^TQglO>MJ>HRVU~UtL2s-PEeyK%UIBbmrhG>P=p*PM0@?_1jI#~UJ zEEsyfg1G88gyF@>@1Dka@-Ah#z12K2|HLT#Ypz|dKagCN`3Lp-6IZVKOXB)vAl*Zl zSgf+Q23g2EpZaf+E0|mU8sr~l@y@piiLo%2uP0 zhKAYz#8n%LfFma=djcqphU0*;jWkkhB$69@lEYDrF50g)L0(U-UjF3xQ*4}wn^J4F z8L%ne%jKp(U~XptyQLvpmu;P! z(XDpyl-&L_<(gbAhz!}>R2EvM!`lq%xnk?bVYxXXxioUaS#5!9{HhB=jKiEX0IIu{ z#Pt~8n%B7;i=~mW>1>%ZR6F@?kdn?EIEAKjO{jA01s1X`X-5|tMU6oYbof{hS8a#T z%naJ7XGROG5JWc5kj9Dd_Li_7f&RK`2Vo_yt9BH2r+kW7r_y+IR`kY@j~(8R`k0|# z*_dw4G}jN#OyKfrCn$|sUX4dG9*jwe+Q9_2%JOO#VHI6o!Nd2^WvK~}#`=oHUWZH+ zC0t+aiYr&`CUN_lcVqN0ufprrs_FP~gmu@QF^gBc6+~0*wbmq2g0$lvX(PA1CCW^Q8rLyPRL}NRqgHc7lR^C4Xdq8@AA#+<%rzE(=QabUC~}K% zE2dVuRW_ji!xDuPfZ)m|V3!^MYL+Mm;@VXQA=KRn+g*uh_&%7Tg-aCHn3@hDjVw_P zMH)KiFc2JChR}=;7Nt9<_!8v^$$6xeGXNBSiE@;%qr=936C!v|;AqiyjHNBWO*#3u zU08`2KUdhDsj&crX|;8&&8qk}Hzh%Sd4hZgw8nt^u}H?5XHsM=$R97PazXwCNCV_a zY>+=uln~@k!WGUxlem)_R0yG_#xW>QTWyp-MYI6rPbFjdE}{Hs$bvC*ItWfmLl{Q+ zGd+#=NlU&T@=R1`Q79JX&j!bb`Ew9))wxUp%!8O-#ROqU?I=OHX6S z1xP|=E(F2RWs+a_C5sLL{Y4^ju_aQ? zzbrZc@~@CFvP&TUDzad_yawW`*Aa$6{tZv#JUO`}vXqw&QEyTt7UJIm$A|b%MDPrQ zNq~6nwk10z1{)#*@b8FN;`mbUGK+>qZNz&>KsDY6!OyNpZrz70HU#ei)88-)EtG=8czhT;9QSUoC7BRGRUC$-`I3nZW(UxMH(8iZ#0vJe|vP2pdQ z0i-!lW%Z!plDo2YYc<>pjbUBMswsSkNDkGK1)x4m(xdeV${!AX6x7#88cY}g;;NCNKsP0e zvQ4l+eUu1qUZAsBWP-l&)X)DqQsBeulbj~&)uG$u%86PaF98e!4ImcQ#103-| zeLG=ChfNHqj}vX%TiPO^zJst5L48MI>l^UdrkTw%=JN*pI&uRZN@H++Jd$w(UP_F` z^<9KjF0N02G;hFz*tkAXl*kQuT;T@1#A9#3dlim>cA9EK`y^4q8}MYT(8%0rlh?m`#huXKU4jAxt6 z4R}y?=>eby;}66&Zonh-G2WGk^oTl`qJtJE@U{%VWRF zsCG^3oR&16wH7{drP(&(pCSr*GoFkgT|)fRkOkxCbP(K(M;J!@Gd+#-Qp+b>tIncS z?27(uaD2=^2NB$jXA&?U#P4FD{z-^OQ2#uUOdNIUd}h(}!8Dw@0BNYtg&?>eFA8+e zvhWb@UnC+ITOyVT2KO%!cCrbVl5e2*GSPUs)+qHe-NGfu8WXM+$?LRa*!5g5iP5SA<=+54%I6(48FT7JB%tt{KyW`^ za_gpKA#sJ@B9gaiNvXeih|BulCh5uL-wwW4f0Iq!fi#$KCkXDoivn!|i?U6yT+iJi ze2*op`_*$wl2#`WAUsvq!GqgD@!rf%YT&Vn&?J!}FFsfR#~>v@tkR8N`BK=)rGG`f0rjs%<2PDk0MG>0 zZ)5eS9F5?-{f^WI_3x2@di(%_yYL9jq-7yCqME{g63L&nWC5uEBI(h31m*tMS*Tg7G;}Yf%+dJ{HG+ zR@40LC&m-mmxS6FWM2x&u3B2kj79ckgjFuGFAHfPJBf|#%ZU;q`|`MQ)d~`KQdKc4 zbW`ORc&D*8yss!~0Pic2F}_RizB004)T{#Hs#Ot&;e9nvWBe|{vr(;1saTA!1jont zH4t&tnoKgg2u}kh30our^lOP^;#gB_GmE#2Fs2Md8tStSh^q#P0^Of1JcRaDA~M(# zu}m;%zpk*8O<0e71Gqy(<4~@U(0*H7yJ`$VAMM9VM0!MRN6|vG zXN{?89BE_;zdh2>IXi&3YDa`-e6Xl;(0(V$Io`?{z>1IdI}1BHY+}%U7tuDs(iTDc ziNZ=m`(1_Inc9K37W^*)i~LSz;@zX#)>f6B+SZB_0Cyqa?*`2=fIkVzu9_^x#sdEC z!YT^*km%tTr>YSJ=9Ac%zlZ1{=I@CsSMex6!e8*);rf2udeC{;tbSeV}*93SRu5pmU2CZV1cp&muW*bEV% zuM^qCVW#StrQi#=G*VHkX&`t%UR3CwqyZZ0y`K@!h)C8F(MH&)lq0u1RGI-%gGvpe zy3tn+RB94U-2|1`XGA470kNbR)Syxeu3hCI^ifGkM59ukqJ^l$8dFm%X#|zpkcKXq z3F4|*2n{N+sB%zgw&a{+CVn2z%_#=dJP2CCyJ5{pSEfa7D* ziHP9mF_;8Q;+;~-j)}pBh``awB9=J5)G5rO7i-#xQ;~pboCbp5#E{&&4_T~6BJbnk zGeqP}OT;SQEIQ8;c5?Y=lW*32=ZMC0wZ`zG^SoF+I0FdjoWbXl+KbK$kbrtz2!dPi z2+j0mA$t0TzZtqnBrn#I1&hv0Bt2S>p!`e0_YlOtZ+scjV8Z1fxbZFubW^e@+XQRT zd8G(nWeMv>wc-70a?6AFYanXi{aR6dov#}3e!XbwCh*STPk3h&uuE?MHSm5Tu3dE# zLLc65mWcF-x`m>J@Xi`j)2*Ztc)ty4=$zX@Ty+ORGd@^UIq-g`Tf{V8O@ zXn7h0KPHYa4DQc*8t0{!M*BxzB+tV>^&BN)vHf{)d~AOK5m&v)Bw#y!q88ZR+=5BL zR)|3ROCpsxw$#ha(%~ynuON;(yb6Ldek8N*KNcE7_SZ$^4NJr--XQy%!cH#!E%FVr zcZ$ZhwZ<^AzZ0uRTF#1CjhtOBNveN0J_` zM^OI9;75`D6Qsd}PeE`WUKHr2WKp&W7P5aX!e3azx>0Rp|B~GDko_x&8f5=kRDa{E z2C{!Enz{+HbMO<{*#zv;??4T*e~)Wd{eaL%_8%o8J)(Z1Xd$w*#?rYYpSD-e0>ek;;h3X%s z$S($zaq3omUAne~XE4b5L+W4T&E(|ttsdC6X7(VGk6+!KzO@k2sxmx%t0%5-^Iqcm z=LsT5LNwTCdxc9er*QRR2`a}50;712n4H4ZTa*?wQD8+M=If9ecD>NP$c%382ZCn= zQk0YPEMcVt(d0C)3K3aUi^yqQo~8b2T>XWY=v)T~yE8Qkc-#d;{ZqO4qYqu~Lb~9^ zP_T4dsilP7ncCU%SYzwb+XREC%#*spV`6Y- z1zNr|w8tzSmO-+smX)I843}dimJ@c-1q63J`aqB6A&m6{iM@VUL3D8aup+K-s*uE; zRApjqtI~BtDyO$)aVUn$(N25qu(D*w+F=zkR?usQb)l>L;h4(Q1D@HsYCN3 zWvOAvhB^%g!S7s18M;oag07Qyw$}&|8L35b(itH`&6~obL?YSH4Zw$?%Ows*wIL*6 z(?%fpnF~>;ZK4UG>vu->VVHa&J&vp{w@s_Y|Mtga-Gr8q0&vt>RS)NT0)f0Wy zsL`&XX+bZ~=%30utRp-F%(-G5&s?UlDcGO8ftqF7BwXVe144h9w!1{6S5!4c3zuoE zIW_G;8d;|8i8OQ)Z>r-r7!aEA!J>306@PJSZ^^ljl`}wXf0?$gu%koAU#6)k;G1K` z_7jCQT48D@G-g@HiiI1K$BQxB*pMsbQDd~X@TjrqHxKBw3br$a<%oBgr`0^^s)j78+7y(W`RE$i=iAO*VsCyran)aP6u_gc!;> zX&g-TCW-55(#&gpG#QPRy{LaQSqoCaN0YJFIDH(_j@0}$m{QP!L6Zk@RVzX>;b^y> zaQ1O!`iF0Tkg|DclUy@{T;a{jEMZuqSj}ciYC|+_87tqGY}52`r>i;0pUKJw<^W!9 zC+pxrW&?Ae6vz$CLAb&RLK1hRz{sEq^<`m6W)pKTOHnyi)ZWA#B8sh=c}EHRmK@3q z9rID}VNig6IUEE(Q6a@SInNqa4qf9N%6p`U9Hm8MBjZ`?Z)A=ZUgDbn7-4s&HZC#Z zV_M1I%>2(?%56bA42av%%tgAZI>bEfs&&mm8=7NH! zOIG35II4xZeCb>YI>10vUzz4Y3QhzLGTd;LNi8Kl3^YW%Bd`l}#?S=*|zIh3)io$Cz|EyRz7VCB(_b@cO za1YZdr54y3>|x#(f$$#Y9i*WN-vx2idm<3s!>~@l9_D?K{I4gu6Ka^Shxs3>rapjL z)Q=@bwlW{Gz!F;-K6NeTBFbvtm>tbWG^gwx4X1$K(fkjN{bOYIcQv0-leeq+6xVpj zg%D#rC+&p!^SQ+J{P}{{dRIe(!@HUj1P{Lu znh8ns^@L2`+C> z%`Z|AH#NWF3J1OCMqDb6#b` zf?G$Etrv#%uW*$3os^)KgEJMhwlB2CY*+dr8PCb2$f&WhRjCkGnOl`bA&jjGiM>_n zFFLqY8GtKSEhcd%wF;WOu!f-x3+=NvEQ?E4Y*>~cqe5?3)+vFrL1U;TkqrZKDG+=N zgD|{NS;o^E{?;#OeYGqF3b!lEAz5!%md6!7dy#l#yTZyxwks=&T*1uqw<{|#OK7{Y zGEz{1RY34Hi)7dR#)4%!neEDIBC@&`NewEyjkry*Of}n-N>P+->Kfp~)Gm~x){6aPrM2Wqr{<j`(DI;T*s2nYzyBtO8Z&Efu z3^mvg#8n$1H2#k2QGY~wS{EX zjmIMFqODEJmLj~BC9Ip#-lS|zZh4!OZ6InkDcg$bF}`ZlXsl>j(3=$Q%gfrN1Sn)S zCmhGzoUj?#m)n7w&B-`iyJ~xcx(i|d4ib?bQ9Dw!aC5?1Q`1hQkCrtbDMI z*-Iq%_9S^vzvwomXd9?~pa%6}36X8fzAT``wuSGd#4huS6&kZmnZn}B-llLe=xs_D z-1&aUPR z4U~josi32Wr?cNng)5_cE}3%fHl0mGxNxoKK!13P{KM@gp1;ix0DULTUgAPXZ*dpEz#H^T47SRIl=I=mGVU~`tCUq(jQLWQJ z@HLQV&>hO+F=&BD=4&7kInxrcY%mMuvxJ>!1GITxIi4-r&MDAluNTiHx4iY@c@Q=0 z#q&k=1-@$F!iA!#8?6^P2Dn~iGZ1zD18UZb7vb7f7bDaF0{btKh{m-`DO$K*WUZ;` zGSbL;@p7c0ldk}A)s+YhGO?&~){9q3&a17Q!SwRii`NLdNZ%XKyH>PaXK4%2Lw-Kz zdSNAk-VMU;Ozny}fg7(inRG)-S{48Px;WHf6pgfj?@q}J;Jb^A$}R)n z-N=T)a}NlfmLUuS-+i9ed8Lh0_fs|&`5pkrN4^IU!3Ri8^1jIqRgg^*fxd@DHgV{w zN0>!_lO3p1k0KQ{dkh5MABhUxt297kpNCdYh{%(ch&IATtEb2<53Qbts6ne|MD?@2 zYRvZML{m3HEA|`Fip@Zbc^=fD)eE@B2Tcflw0cP*8m(TYXdzm$*3|S0X#}laMH;&0 zH4yx!2SS5ZEUFx|dP8!)Y2^&&gpXEl2|IDf1m9(Ming~cZ4tD3M_7qy^{%k>5{-jT zrCXX85LPWmta=anW3cLdB;)HTDLfXdJ`h$HuXY-J2{tgi*hU z$gh@&Ho?ZI-^eWwqke~|!Kitn`VU_?lU{L>jtfVGukZLTE6GMU{h5y(MQKD`zkpe2nTV?8E^R zU{pWRwuq%If>9O1O2nu|h25Fj!yChSRaeu{tiLo{Kv=aCv8q4HiNUG?NXD}yF(MYL z78h0*uxbfp09KLMShb|+AyzGgD?B!mc=)u+;6~yw&O*B>FuZ80jakcx24L2*WbD*s z%vuiFFp!o9!LufWVa!_5(>hOn$3AA$8#Pg_#2m5MwK6z9cCCU4o;ooJ*tJAVzoW8j zqzHzsCOHy^q*|R>I${;7O7KwEH9&B(nkdq}O=Ch>ww8#jZHZ`8Y%Ci{Zh2U?4nz%> z4HDH=zG`6EVA0f#u#A03EMqeefz|~zShgOnT{Q%uk7Yw8qOoikMGMzktTilu_=gEQ z(T3nI{^6qShyrak=p9LJd7yU`L=EU2Evk?4RRi?eMN>BdJ&pl_9-DzsH5b%?UI(u6 zpa`K4ddEpbgWmBJEd)K*nwm}^jey>XNJA%|1cG08L1;jaMU?}3r%29It(?L1@%wJHzw)+6ejjRIm&?;IrK z=V7GuSkyaDSmmPL`H%+ck=UqrfhZyBU5G0jP$zLGwK{4Ww~cGYeL=4QFra9o4SN?! zZouBfWUSX^*t-PTFmx^jan)rA!?1U`r#1N=zHgqog0iu=cO^JJ?p=ilK2%~7a1ZYS z6ZgC-qJnIc2=HAavWWvvUCS)qJ$zr4x(=zR+4Ufyo+kZr0R&RfCx;d}vWIBp~93zg0{x2d{x zemF$hW)H`^H2i1bTFac#_04s8ybO;|Tbrj<#=gK+_zF%us^~L6pMSV zm|wz`t6r9P@}t$}8m|d3+G(W?%dbdY!1AkPY|>>|eht|$u3ran)f))Iu>7W{HTi*s zXPkPAlChxN362lSZzJNWcbEiFmIoG|22_sC5rO1)MKW_hV{-G7h1HQ>T13O zcDk;u754(wpO8ai(F(jJtT84xc_GBmw||L}f?|WWg#Tu?j*^A^12HtxzaaRnp8?WH zIj>}zE0X~)SQ)pn5JX(nQwz#>Q=VHnwL7{M9C^AhOf_DmmzbUCReB3spG7B7QThPe zpyT|{RVN4EPMP}~W9U@+Kzoc+>5F7n^^>AQPQ^1^oXR4?F4w74KpIYk#C9r+iV`}N z{)8N^kqNPgX!EIQ;+Ruz%eED_5B<4{%?cA^D=L#Y&PYZPd+9m<;Imgi8`f~avQ zYm4fEzG{HZI-;o?ITZFk9SWO)ZeS3oaVS-|#$z*tzC&48BGRmCJ&G1O6xN!WhLA=a z%21@ClZS!0YB)mUP*_ws4rP7GIl{^rOf27_j1+ca->XsJ8;7!iDBMshl*uv~2Q?@7 zlZ_yTwxSX6CmLRSf3mUYC@3}XCz~)^N2xM4g%p}-G>EG<6P-@ZE11Sc-O1)6xP=z9 z+zH07{&;muVI@NLR>IbAS*Dw6r#7T(@Tg`1Jw{6rwzozJF|fT2l5wD*6mP>e4Hw8B zBdns39e&GlEHVJKNo>^KPV^A9$KeW}Xh}SAD-bjSx|&AXu)Txi1#Is~MykuOy%Vyb zcgKUcYG;ID*xtp{ns|pMFiuUNY%Fq51jk42T@i8BZcOs-&;&YAK{iPQyeEll!9e!G zdor`=J2ZhRwL4N#vuY4m?I9|3uhIaG-`-o6dx}WP646H3h`SfL<Z~#g(htBp&`* zoM55M(-tF*fgwg?ZSgCTFn-ZlXrwxb zd16t_1;0YNnAyhj`M2@yZv@tfS9Ybz;sMZcqgKBd{b%(DSsCKMq>PD!>ek7`~8Hh#4ff`gh z9@nlq0ilm-CrU)4+DQ~GL^al$nocH-pxP-&L${m?f^+l`8dPIZ<)GT>lJg8JXE0ZM zR6A4Hi9;tqwX;Oq*_O5ls+}XOL{vLh*!sl)4#EZa?sz|9*?G_(gJtI<83*-A;jvhD zp|HAuW&c42U>S*xWfzGaV%f#G!go#*PkeXWGy#SaO|%j0QppJfyNrx}T}H6Wkqraq z3J`oEg)od@S9w|!Z^atZ)YX)X#jR_=@p0=~L|kU0wbzFHCmx;I&P2%~Nhky|YhZGw$aw~<>OM%@lkgHd;g>N|baz^J=K zQ#ZmW_8BpX%|K+i8`NObJ-EixEQCHr-6s)^QTJ1{5TjUYYI=Y)f>9454c+n(2%csk zG#JIA%E72dBp_uy-U!;*eDDGK+q9JgQK=2OjGBJ_x>Q5=FYVX-o*qJ`j-)EfH;s zjb$H^TOO8u3{it+pNQ&DebvCS&qPxj{aPr^A$uSk^LUdR^V@#)bv_0{K{C+3zSP2FvCl*;Rjt5wTeIr?9$!Wq%<9 zu#CjUvcE+SvFsmQx$0kuCt_K&DKNZfs*Pnm7GvK7%ND{#W^9+StS7QzAT11n52_G` zv8=bJH4)3ACaONn5sPJg!SS)IA0jw4k4YYuMKz(aY@`U5RY;D+A*mJx-@~$~Le(EU z)O7#|zIqZxy0>Xe2+I~1ktHkScV@z_MjUQ#Zmg_93y1 z%|HZN4%A@T^0>wqQwV)5TTvn!%T}UjA(pY$)U+~b1j|-I8oFgw5Lc~+&|n#hDhJC} zmzrY#kI517w4c?5ZlUAQs353#$u2wk|RN$VhA;TTk>5$cEs`RYN5n{uMCmW>}~l zFtBK+jbg(jJ5X#m8GX8pV(TLthR_HQd`g8djAElat@A>^QkG<&+JNG*5Vj#WK7?(A z2!29}Nq{gwRk*uRO}0%0zcvx^#9^p5WtNUYZE7?asN!ZI_|{3Z=pLpSA@JHlM7Fd< zv>i5hZAET*;I%bG4R~!Ms<-u31H8tFrfvjY>^*`Pn}Lus7Sw>(cDTmJQV4zU+Fl|W zymp{yA$YOY)U+dM1iW@a8oFgX2%aAyG~mUe$^oxkB#8DG~*RG;% zH%prauhiKXp55scN!(FusKr-;Ew!zgyqW}q&EwI@VtgXJ?k?=k)Fhd2mXZbYvgFD{ z*J_jzgRXlZ8J~cO0XDkkJoDutX-e2d5!U*4XD>(tUP)|t-CL9pUiZP3tM-++lNyXl z$GkfdYRsy-=Ela_Ci%5RT5RL&6ww2m-H(iwyNt6n$cE9rKM0NnL>R`|sh-v%IBRv7 zs-t);&entTf6ZNIm=wj}) zIl!88&iR_N*PL_Ca?R?JGga6fY3y9d}di@_FcP}cM~UCGsPD$tO!=mo(kPpVh&I9jTJEL5ckVypSMy4b{m zG&YUG+Pkvgu|R|u8p66#X7E@2OkC@Hhf_=%6D(aLOL8ZU?cbYJ$hnqPf`6 zEIsjF@K_@3@FCa=zPtM77%_OPHW-@>xYqP|TUUf1C&Ch% z`Xmrroh;?HSdMe7v^)gHqR>-B@Kh}rw2J36VTFdN(}k^f!|UmPZ8qMtqL%SQ8KurZ z5dl%^Ol0E=Qc}JdrSJsnWjtpKtIY^izKrJ_C?H6Ym_h1XvBMyB9`5koO46YlOpR8+ zfS{LVWV%3<5t%L|BiioBbP?3hzZZkxbr!DWk?B&$YUplw!#i~ug#+W#<=}X6=?Wz9 z&Wc%xOWX}_7(o@;D!!<6l?Yc1cyA@ozp0{k!yC5L)yPKWt^vWjE3u(_mM)aR_jMw2 zy&`xdd(f#91xNBCwl5Oi+^b>aIq+~Y()Ts`={ zLlPRk|3lGA_-3tX=}uA~eBXsUbj#f!wz>yb7rt3kHSm3}Xx?XNmL3ZazV8=y=$I+Z z{T~o(4;t2df4F!^SfP;hu&|fLW^g1I;)N9jR=X0c9)a-yuzD2Pwt7rT4g{;mh1CwQ zdIAanD-si|o)kL-tEX^>7gv&QiLDwuqn7$(AkjY)rk)Wsz|^y3?AmUadJbwBGS7qH zO%|@@F!iEiby=H!sh21g2v9GB;{ntwNZz!_aq}i^GGW89*s|J?PZlO^Fa~3dbue-3H?a=f`kjo~?Z&M? zpoUTPCkWnJ;aZMco%(C5p|~aPtIiY)#H}vic(~OS3A~JAmV;ZOj%u-~e7Mz3#6m}+ z>JGkxTiS^p$Us$kg5U*|XzN~Pu^P9WANajRWFrLriyk79L$#zF z3{V&NxDV@s47|<@TDANUOI&_a>Ur&VBH-z=@GQ;9na;poA;~?sW#Tqd^-ZPC_ zZ6KC9P*@}wFf6heIKn4@x?yoc+}mm+T)nWku_UBd)Fu?I42!HaEp1Bb3yYf}4;{2Q z2tLe&tNXmLDBVGAf4XO)Xl`L>mN3=}i(3lYKXklL_msloB(XNxu;vSkTL~*PEKU*j z(%7CDghiZM6;ISA7Xsh#s!ZKaUAHug0R<%)b zTSy~Hl9*9)J2Ap2xjpXi0Vhef#I{Dg1O5;m*c48aOq!X?B6xC{Tq3O`#Yo9|n2~b2 zlz>RNBN;XAj+8T?hJm&d2)+@8Yk8!c=~!JRpLwgY3ThW>1qRMp;CO*^S0rq;8?z8N zR}L8)s5BeX7e{A{R_M@GbEwi9YE(tRN4<9k!8;N$riTTc!UG1}bHZv&MD{d940qhH zx|guS-PxObH@58~7UybLY1Ut;7jkX|OH?;B`NS@eaFQA?^nx^1ee{g97Z#X<1x zBV1kBV38)SyROuWWI{`7SBwEiSCYc>*R1491Ng2hhN@~rK3qwG*eWeXbOWn5Y|m?hL{Yw)rFWQh`J#rE2eXvY1FJ)EOnp|!^egphRwiUZUJ>ejKV!WWQ401 zVhWOwo>4`LR)!eXnwI91`a;YCHd) zAjH^W?I6Qi383X`9|sF7G{hVtY`u=f!PONSTm~|@9Ew5$g3DpZw$LRi%X zmm?vK;6h>sm!rf8gUivl!#Q`74qc7sZv+f1`e_D_C1L@=qm_(-?G7HtKn+9aSP)ws zhiiH8INq_kEH<*u_~-PKI)Ujpy5SgsRN-QM+4E2%|Hyh7}Q0>OK@+iOL6tk@G?ngG`yUm zm1xLX)6x~BJ~X@%dFbS;KyV%%t}Ys~sA|ygYSFyL&@4S|9vWUN>^Az|J>=y&v39*- z&4-3J2rCo~ZxnXfgd2ZMRfSsTW&4VmaL*wo-h`q8F!5$&Rw#S zk?}sq>hh-5WqqdZr&b_7J^+q~j}IbYtB06XKCLdZhDx)^d?@*_XoU_?^$1nUrqyLe z)uZ5}-j9LU>TxlqJD*OKVdWDd@}wbRxZ`5wQ^F2)r-YSHi?wGeteIH(EVOfe@kwL6vGZ5ik0(G(SW!&596S85}ss=0H6wS8`&C>JdVddMxZlmvAtb9kTy=z$WVdZHNIDcJE1IFPn3ffK^wz}5&&3XK@(VHswHqhDgc^p@S0MOA60YSq z`Hf>WbU%mRQS~h~0x|MCa6F9s9tj*t$1GqZ_on$R;b~%1`S9^a(Fh%s>L;q`y=i`f z>Syp!*Iz(vwM-1@4yQ9^*!Zi6{AP$4uDICvyRgGu`2&3SXa1jJ@Gou9`+_@v-giRX zN2mN<mZ#{C5T)74km%-UVq?qALjAd5E&E1dGtme#IiaZX(>>5Z2W(!MO*y)q!(Q zh`Qk1OHB9nOru6CiKPw%&K!~iXEpnS{2Cv;^-ovE^p)q8Hu$RX6K&>h*t(Yh>l~H7M6ci9e{)uc` zts!2RQN(iUAb;YH2)o)yG7{2=BqU}eSyPNKlB|V0TdghWmaxAM2Q>zs1^R2ok#)oh z;>fyWOl@}@83i?r`q3bGp@nOC99hq?8hWx!rJHJf>I6oTvEX=-WE>KP%^-y_s0syuz9Z=KmtMIxwFIQ5Vd&5Ytsl^Q~}i zt0}m8U_Mn68qB9rv=Yo&Yg*cx)CcCe09w-?PF49(J$=Yjcj zVTbm;+7Wzr#q|s^xRW**8;#+<2Y@plDP{}lOr(%XMl^;-^n%bxIv=T5NvzIGsGXsN zmZM8pTdje~TU$L-ELQkXT3fvf)mqzE;wO%rJTdz&|bK+)!veBk#edkAfmld`_Q zN3$Mt#hy_QI8x@ozEo&!e|fdgL&NU}f{iy)N{i(O`boi^#%t$H`aS z$eR#eXyi=_dugl&ZC_oRjMj}Zrrq7e_}hTuq?0;3om8xodNd;6Rw;2t^CF|`Gx2;rlFo*o@^6l-F{zRCbslU6%oQ@o zwpEi9=yz4-30YyaIZxo~Oz}zOAdG1Oi8)PZ78{%a3>G>@m&FDKwY*wH{%;tVzb`SX zw?DE+r~X9s4#1tQ4wQ6Dj0@>>U*U0M&7GLv**P@a7P*Qi&RbD`5LH?YGwNXE!2d%) zY;~xp>rP|AI?nfiad>i=h#am(V(V7hLN(={_I5lyLhOWldL;PpwEAMyQP4n5jt0TY zD>1KYLdSJY2I!hB5s_9cVo4X2wdP>Q$74hy+{a_VhmXNMdmNZ>=XelXogkL9J1kwh z_k=6ET&)y*6)gQz=myj)CQ;h9E_t`tivdgjO| zQ>){L^Tn2+54D(B9POr(4e5l8Von^{3hc_OK;4Pszj1G?tLd@(SAc6IAswQwrD)~E zk(H*U>qvbQ$Lo=Y{<#6fRyX464hgNB&4y+Pm%WMOEyDJX8t<Q?gI znd5C@@pf%7HWdvy4IlE#PmD|yz?`^WAfCsYn=@(sg=u}h|I|{(e(DZbLz~iBZr39$ zl(y^rM~bTOt~8~*Qv~!TRL2)}7xK_>cY|P)j0ouS>Ky@;#)@E6Z>q8CUXi@dk(`KX z{Xgn+Kg>8K=y{s8g9CLBuz;vLoMm5wG@CUS0!yrYag9wt;q7k3XfKSVxt_D1j5ro*cgqBVi?B z05R+l+}r9=TrprRX%0Ngk4aiT43G2PvRE?xly$Ami^l26$P>s(rVf}(?>UuK7Q2Uq zJW1O6_nJsO1!WA1r$O-bAza<3iSFvBsTmI8PJTtWBmP;De@@HCHb?JF&lZx(dApF0 z#3OU2&WhwzWKMKuL?(TaL~?!_r>7TkU~ZR~nJjE08R~f$@dkQqF--lPznz)5R8#f$ zqsp`@=BDZex>kDXUX<##@zlLU`PTnmbG!^2=#W=HuwzI{Y_Xg+VyjC}$h`bD5qVvU z$nOgc7T&!44Pk}O%a;n<`yxpd-&}3GxgzctNv3m#{$E%Rn4!OkY+Jo0MeDFya$08S zZwsr<8M?8h;~hw2icVtAVc!)aoT9&nJM2V~v~jNe9OEYlKSttK9s`jcnv?VoL>H6v z56PI`-bwmL&_aKH41%-ra4nytf8rQ5j#UlzO?^tq-}IERe8&D6INl%aK1aeet9bt-b-V)wg0n_a=*%A?mI%{Z2%_ zH$)5{+!^K%!VdMJG|~D|to>AB&75fcOm1}(tzRJOM!RKV`d801!1*_^S`mpSX+S8W>^tnEX`<47Ubvr-m? zLdTX)_@xjq(PE`(sWaIAiB=cnp^v+Q;C&dbZfIapIyAIB(ds6e-3`ssv*k^+dI-CX zu6N&s_Y`Zr3~MFikX4kug%t{SD+ya~s+BM6V9ijQZ!fAuyY+~6ePBEQ?fN1c@4%$w zK(y;GtZLD20HlF-BqrJo6eC2tLAbNkU`ZR_Uh*S~ENmIgHTQJT1iO_*6<{}njP=?J zc0-|sA+rhyPNu`P9PEZUMvYG|1-hnIqhKJ`4F|`=x)Dg&YISA->wI7HV_W#3?w=wV zI@Z)0RM9^-+!3N8$U~Jzf?!LN7|=b*!po3uEfHDU5HVbEk!~Gfhq_Qgx^>0cs0wQ) z(v2p!I;0x|Q5Wgf6VvN^rU4aW#Zt#XIt~CL9b19;G!E27x*FW$6G^ywNVkC`G}29= zXys2zR+^SJB=!BI+z5H-)e~Gn; zhBY73Z6T~sq}x*1`n%E%iEOgqOua`3{({0m!!^r+I&L#e*A)xNF{#N!yGbY@0PQ9t z+g4ji>49iBMOba3UHN$@Q=tIBBQXJQn%E)WZH+ryZ6oQh>7CI87*TZ6M7(W97l^kV z8I#+Kc-un@LuUsNTTREc9PxH^j2d4pDnmTOH#LK@fuOe&I3DQjjD)RbG7F%`!%hq% zs34ofhkLt-aOlWWv#6pEJ27mjU6GBt?FM42*6r#t?Io5v4p_0{2v%$bLd@QvE?Dh@d%TUp)dQ=2C85EpmZFtl z#Y)rCexyFIiX#ubQU_wIdR$$wVo}wARYEkAhGyxR@W84;*r7wFw12WutfdTVKCns) zD-^6OVe4ZBF!*wbwhlX~9;bGaw?wcVfKwS{<1LXC9Eej{VYLINa!}x#A`la&n#GR1 zDZ(Az6iM1R>co!)s6ECJ{WBpdFKT>EM8;0-g{UI5Fkt3`;58Ah0I`5a5cRmtxm$##UvJ04JMr| znx`0=rH8=7q*H|*I$BDYbedQ@-LU4vq%(vSib-b*dueP34Br)oNYjW&XTfp+BAtzF zTb(1t1|rhA!fFR1od*RV5{ZdO=ZhU8(gnD))rFF7i48?fEB^jj!@6S((K{25E)pf+ z(Zys;YcC#M0xb-dOF?XP8Ls7cbh%@6SsPBND<~9*MpuI4q0v=HV9yh?fJS`9=TwQc z_hHf1A{9Ei)HPIb&iz2UsB4i%HLe4()%BvRyN-pHA<+#Ya-$)li#L(zCUUDoqMIS= zBGD~k`c}_0kmxqC)NzoAT}32fD-b_!2X&F?4%}mB6RsW--6;u;M0ZiN5{X!8TDqIm zheY=v5500Ph^_9!)kPu}RSgo|FPaY+nx*0IA<=`v4jn5cBzj1!J#1L>A<-kk3Pqwv zg}pSkJ%%pUR<&_(ef3kL2?V0YU^oDX9!IvVo{&-lf#^wLwF8Krf&zeu!~~+J#SVe! z8Qj_GSxL9Vh6Dl;s*Vvv=S&=WPIQ1n&yz8sy*Ts&v@ld&1hLgixR&G4%Z|}y;XbKX zC=&=nuY%*j&}&H8>UCxThPvv$M1@#&9}2x8LZKr|Eu~7UYeW4PNz~y@5WH0pUEOUg zvJ8aY7Lj)h5nZ|oLhq7W9SFS#Q5S^X7t=1~4!=0^umvl>PSQrpFGYC3pg3%wM2Qd1Rj9KjkqraeqA=3$~ z>}}N<*K#oGf*cxM*0x`&E9C+K=^x;DfYc2MTXkm^0I7!tB&T9*1|KN(5W&!qrh0;p zXTY$ddLaw-=?#K?OQNs4kwupQQy&rOYlvtMOknCqZgs%aAEGWW4G_}pD za6GKq2nkzl%q(D4;F&0F9Uo+EBJ!bQP;E+;z%x-c0|%Ad90cdni5cC)bVMVUvv_u* zh-_hq7>>9v{I(Q!s3WBpev`!7*%4{?rNH&UA=m1qIsISemYeKl^GFfGDHk_ zT&Te%DqF~{4k{HyU8u~9>4Ik(P+1g99S15oFbI`w1p?fBP!}o} z;NDgXarK~bkt8%!?oZK5sAQ#S=>Sq6R33;t^sxEZLB z@=#&7(e;2z@1N{rJWR|UUNT$0kMRhL^I28fEL^(Yzf^$eS_6 z-MY9~Ompkv65QFURnjdnoQ2S7XW1ed!8+(dGF!;2W2ld}FeG}HrR+{TR#YmgTPou? zDzpZgJRU4`$O#~}I#CR@SWY=~NS-@cAbgUDoUBD;fw1F;w*m1K;f2PPQ-!@$&bSL( zI}-8s99Ge^j3KANs5EG4o1yO6I5&tySHju3*?dDz;b?7jI%H=?`!?iqg)BeciM5w` zbp|qRbtbOSp2*-K+sF9dDvw`&VY0l zhw9>ppIW`#G_S4^wQI@jiDT&t>1<1y){g*zf%_Qe1GwNRC%|KtHrg^lZj0AO`2=-3JGw6H~ zyPsm+qJ16zxWN@pKR~(E(KDkX(BnB(i>l-j=!{yOOyNs`8QeYyvFHF+AP>b9%ID`9 z)kDngmPpnW8`ZQ2|{@fv`M zzIhCnY_X|!As;*SIP%b`{S(Ee=2~wA=hYL)$HRy*lg>8e9N{OmaK8m{m1SLEHyLkI zPl@ahc3VR_Bb{GcNH(D=817Gl8SM$)xOFzzIH8_la$s^H4kzi$L-DbM>-h55Q)j9L8~)8(p&TOkTYr`GeSc z`C?rmT|h;36TT`oSJJ0;5)tO9*F?A<9|vO~zb?7`eLbe$Kz6iSvCuGXbG4NBy&Y40 zi2kcBrL$%yt2ZguOH{_?(Ohpa-5&>R=i_zo%W1^7MYk7#rWszO7piwC#wRXbSGypc zD5TW8$eGbI+OK?&s`n_^EjnjAxb!~ndpIYYs}GP$6{7vIw!MI(&-px}VGHU*L=Xe&+E93PCZ@<1N;+kzPAn>z11&ZW0tc_WPcS|nck-!##{z- zh-h~$seS{GTWxsqt0d_1+DHHd%x-bR1#eulLQeM_Ofmh~HNx3H#SM{}ybbqm%Kq;|IUVCF1~ zf3UXpz^(|__bzb7R$aw8?fYzQw2)TweE)~xdpG({3(NIAX?=|^f23m8cKFV9sxEa~ zY8C55{N+704-?>sbsH9hrbg=h`D>=WOs!>2V;x6Xd*fV#R8)ToZv*Q{h*_NHx*m5I zk9!y%m*$F|$2|>?d(mTBSgyx2ty%PMbL#~*`b6t_IzGudhrKyjFIU~lDll`3H3kM# z(=1sZv7ObABHLSo+2-S|kGRQZy57RHqcw=e8f9i}EkcX973nP%S;?qKk?mF9^nHwq z^kqe8VR;p?{z7lN#q^V6`WwZ_04XnKfKkjq7DEfmD<(BZpI+M2x|nU!U4Og0x7C+D z+sk?%BhUKYsPG{1WU%3h43Kh9RyI5tLQiO6xtsVQK($-cVR%E#TIPebE8WgG5C${XQR|O8S z4&*4Es?UN##$%x>8;UUQ%GCV z;}i7j^&Zv$^7>e>k!)%`Lt_n=V9CF%TR5h6vA(61-K+zcnytTWG(!GhQj88lXvbWy zfO#@7S^wA=Dowr$t~dhaP$J)|rS>J_b=Tn<$LeUzi}rFS&v`WrqI1=1xXNBKqVaGf MY&8PcVqMMu0U^fPpa1{> literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.netns.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.netns.doctree new file mode 100644 index 0000000000000000000000000000000000000000..4c231727814e0e4de256eff89a04222edcef3f96 GIT binary patch literal 152253 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

    6&3@eSZQ_QRa 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.ns3.classes.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.ns3.classes.doctree new file mode 100644 index 0000000000000000000000000000000000000000..10cd63b1e2aa45bb37d16e436ce524674c5d193a GIT binary patch literal 490090 zcmd3P2bdH^`o3AfoU>vEbwR+KQH;Qf;OZEcWp`k9ST@w|64W+_HOEsi=bY1tIcGhy zVmeQ~Gn{vN>Uo}e`hUN-s=KShboH?Cd;SbhS5M8C>#OumP4CeQG&Z$0c6T+mbPj55 zYbtj3lebfftzG>(<{x-W#{yo*f&=RMwl+*DcFkxnc6Kb}bu2ufFm%58=4&msHxE+9 z&bDsVSOj|Ed17<@ zl!n%ZNk!FvN?TKROR;0o+QPmL)`r%mwkh?~8d@d~ZK|KrHlewtxoZY)nu;xA##ny7 zKR+IAJ{>I|cJ%2f?3OLNv8}bUtD&{4zM-+P*iuvtUCnK+F&)08eQOKbWJ~L6Y_D(G ztX;KrwKcZUwtXAhM{PF7RCM&~DeROjLHWMUXm4wVSy69&OBSnjHB@usl=i8cg|_&d zi#vT##l~Xu)M9;0b7xn5QK>eiBkfCA!r5LERdaJ^J)+RwFiFR=rLD6wY_HwqbHv2| zcoaU>?X_f2p^z&+ws16bLn0e2@gwAOEq|$=!tUAfr!*rURIw$Js*+@*%?JAu4`Iby@GXcA3$S*DomrrWtgW6)(2#W1kxu-BNTV8u}>!dA&eT>|6tm16FDaFoG zy&fC1?ZP}7m1AVQFnU+*DGbTh%aJ&Azz@J`wS{f78D$12HkR7zJBw;+QHgd;1G}PT z94k6j?0YBO$xRxl3Y#=dRzCJf{nJ%!D(g?2Zz);E?KT3hv;P}k79i+~}oeKZ!F*tOg`F*~%YYPWw^98fk z)M86pqn-@ov*IphX4}t@L}$izdJ6kx>zLBerJAQ#7_yjjB(MhBa2#K^r?6|b^p>_s z^-UPL8d@8R6?FLFSg$tcq%f@^bHVJlp){uI_p@WV0bdS~1Sox1rY}yeQbS zt9z{Q)PiSku#D9lsm(pmIoii3Ek(8yzFeA(%w?E zN2+nG@yDvcJ+7s6D;BqnZBwRnw>CFo5^S9mo5X6{T6eKO4z1g?C-;|0B+}faK*vnFpx-)C7MbOZmLQ}S&pi5`0`)z}VTib)E(Zif= zKdGTxmcI>Za@*7j3;NBRd1%@`nnAkx!$#WNxxZ-XD%KZUC&Ze4R9A7=)(N4UEqYut zS8+YR%EN{ZkSxGG`EPfz2x)M7T(#}_a%M1l(cIEHrZFI z40f_hPoXY5O0fmADo$xbD_E;tu9nTBc`QHmr-Ttbg$=TW3pnJ5de>T4gJJVH$+ckH zEsvCnh>mZ|?#{(jd`|T__o#Jk7BCC8O`KTY(B9s{d9bb3=iRfmFfKb@rDmW+s<8yd zme^=6$+Cy_ade{C%ek|~a@g-%!OnJMZDGS~gSdtC?H}bN=LqbRk9N*GaUe;2+>_vv zg=^J1x2>I6YhdYuVGGzwXM3@+OLb52Q`om=?^+jJN6|8dqD`DmyRIp$eaWU*`nc*4h>w>V4Ka z=e|}0JMre-uhxZrwy64P?byhNZ6a+uO6`xza75qVxg~FiPkO%Tg<2Q7WMct7*8xsg zC^kY@7@GY-`M{pSCfRK#(}o6Ed>am`b-^l~UB!l`8AP{=038ixp1LLWg&yqe{+TF% zFXj;EiYn+ZvIA`oq2GGEw~%3f(>baweZD=k$2AzrY$iEVi?XA>r?7u^oEzIZyM_)M zQrV(iG(qa@Kfb3hB3t~#=IPjRD!3T+b2q6U+t~>}4f5UK-1@XOOa`1jrMW`*{I-}- zTi80=sD`FeTVpWKNU(-Wjb6Alb~HK{ZBx2iy6`nl=1|_`T(rqfB(bUSy(reY0L&&N zQGHiKb4zqXKhc@dA#QE;QXjkad*~$RgqHX|O9D9-Uvk+C;8IVaIlD1RGi0oELL4G| z50YkYIhvhmG__fEbz|ic9b)&>wc!|Bc8;+X+itRRG{^z|iNmAXCXFxM z2>`RDZCZVDP8ruceN@}DG4`}FrN=d+ri=4)w$=H?Sk~g1=_8BlR9D-au1@G~nT#m| zUou&%S`oT4J{X7k;o)MpqrJxk^T#H%Fk5_YJDeRnb*<*JE9X+LHT?cDy40)nzwio| zdYwIm?Xvq>9mQIN zd)F!5VOO2z{E|C$s1-TDec}+(^q#_~>`+$vf>;EO)n6XRzLT8cgp5}!Qr)q1GC+5%%|c_t(kIDyW|l)h0U`y$SSn4Db+mB`89ll!cl@@?bcC( z;i`SqFqp!#1sz8^p+2(&gb4qOc6{3zd{yqp_^8^#p4o2XoT7YzN7uUI($dz}J|X%A zs?U6kvlFH*seJBZonHV<-As1N(zg3;Cf~Sr9Os;bLo`` zrTDQkzxNM^vy*!Y>tu$fe>-vqCx|*uaZW+0lcMkGsm}ImmLoJlAN2W7bAD%)W4GfA zJKY_$IF8MrNhR?Pjdh&ioX|N)hDj_!WThI${mh=iE}3y3 z7@2KGS4kCdJSqPd$mi7N*=}om);Hr^XS>8!NKsJM7jvF75=qFz=lw&i>nr-qGcD4> zL7nfPhnDaXUW%y5()oHoN?0HmNx77+@;PXk9{^vgznuqLGOnfJ1%p^HnEr!3B$3% z(<1a&?Uy^ha>)Sb{RXAKY2k8l3f z&M#PG#ot|wZSt|&uPcTlz%@=3GCZT_YrfVwCZ()8qd7g6$fT8EAqaMz6TL`&alS#OIqIw<0-vl%)Xdckt5^T<&A zn^Qk7w>dY3i6c8c>+Q9!mAA>>re0% z0Fkq&)Y^jXbFMCA;EbM+@dNTlXGANUKlBCM?@ZjpsO_`PavsZ#eU&NR%PH1yw11$d zFd(}d>%FnB^1<3dOE!J(b+{O_uPoYKfbK&*g{7bq*@Pd4^vBYr3qLgJ?0DEY>12Mp zEb7Pc>t_x%0ks};(YhAly=ak`#dd4X#1uzunWH@YWvd6J!oeK)>SBBs3>;qF6S6W^B7|^3!Zl-ZDg_J8}x#6KummB=d-@(+*b=ogx_~yWSA_rkKtPk z1Cu*ma^`H-fiT~Km!02G#)b`_@fGL6jTo|E)~G)JpPVZKQJg$t{%Wo3Ol+H)MtftyNKEuOL`e}vGfe*gtvQKkXVJ4he%8xx8HF_D)#-lh#G-!686P6 z?i$8^*9kC3e+}tJc(xN@jxQ{I&i86v+bFBk`%LdUM~dXy(dYf3w!3Z_0ol5M=<-B+ zQ*mNv$A@0WM|DfKHz;hsu!`;k7TwwL=R-O^u3NIPTPdtr>h*7DJN{Bz*RQGA*anZ# zq8*>q)-Bu6-PJa+t*xt7j&Nf0rn)*l9XWs9qVhxB=BCb$&%BPm4k#^x*P?a9vqdv_EDi4`}8{m=-&{Dq+*LN z@AFbWycVn5DMOx~18e*=tRU%&(&BYPGo-|i8u}J|Sz4lQn+!hlg=CHV$fSlNMAU8$}}JZiE9j2P}5rMs?k3l^o9Jhv@%|+;I%4VtJMw3 zFoH>!6!A@Ib-dQVYfZe?!mEE~0?YohhErY4mTyaI*KL}iUxT__ni#Kd$m^|4*p~uR(YX#%oi&hTt_6 zuVHv?R=0hIFfK(gw8?K~Dunc>(&l(=f!CIq`GVsUDH;FY(pGqFotf#F>T6`ua*Y3^l+ zc$p@YC&NgRkvY= zUY^tURV^g+qciDwP~WFtSmEn85vG_BCb);mcY?WR1aVpUmtRNGaKI z)S|*Ywr*U8r&ul31V1>fksq95wB`>^vy(^l5!vJN4Y>aKczBgE;HthNYTvr8GR))w z`5OL~KgG{}BA_m_qYHlSX9B;S@*}*M@a~s6D(NpE;!U%-Fz%06Aycsc1*wXc5dH%) zvzN^p%ZMd~?LfQ^s@o(ZU@{&?hC;QJFdketI)h0APh5Kxv9yw7>5he>T3VzYl9}lG zT)HEjmJvCJ;#H5=c)S|$nou`9!&?7Tm_zciBDoQ-rp&>Pu$7}XE+?Xjbz5c_1zfmB zpO8z*)8&PKVrEa4y)Ze1{!^vvGJ{7NNcumJ^2406{4lkym ze0j#9)kVK!upful@tLh-W{qU3 zuPgi~;B_KiCuODv&i&Pdr`r4+TTcY^WUjd?O*-of>&bYXQnyY&|i%Cajp@j^D?LJ*wC#H z&&3x*gGA0BGNaLgu_}EY87$1_<8?vZ9vKk{#%>;Ri!@KlptGq6y%4XNnO13(Ib{c^ zhKPWR@VYoNJjqjLDMQ9kk#z}Pm*RC9UYFx_Mdq&BJ{pDAN?SJ%6RB6?broJ$XZBJ# zqf~M3+)U(LgV(j0*@GiSHD*vVbJXU-cpYBX<8=dGH{x|u9TL7G7K+m|@!Z)$q}*J$ zbq1Hf@RcDkwWUb71+QE2x-D~HlyxzGJs%?ew?#x&c%;U-@c#s9an?S;LBHpx0`T2kJk&C0gW!Y%>cB!@V=OtA>1`kXKaDJhw#3H*UOoW!7rE{-E~h9^-AWx zF2E$3 zX6B|ZGPj1?q~QB1RV#Ad!s~6k-ofi#yk=)QgD)ymoY`9hy_Y%gbHkVX#z~D4*7q}$ zR)1BAZGG!xKLYy**9Vy+BfqQkvpv%9#)7%Kt`D9|($a*lAk{d$KSb?|Yy3IDo%(2F zKUIeh2OgvLL*c3YamDk1Rl_v>-K8p^qHeyrMesc*#wv9H-j)`qTf}^NAl~u^1cOU$ zQ;LHdTJQ+2!Kw&Qjsw_WJZyMyXM3r+b^73X{N@bj>sepnvBLNq;mE`jU z$~wf&crzd#V|-!UQtYS7_zV%AjKWhbLRglt=KO(^ngZIg1imb7RF;^RB}`>TXJIN) ztx}=m(T3XrWk#V)=gV}tOmEBdt-GwfDMx&02V>lYeT&n(`l$|llGj`X+7pgZohUrj zg{$_q9J(Qa=$_EfJ)vxJubZ?}1KPUE{+1;PjHA=YP{C0(9iNtdZO{&@8S-xX2IKg` zQO6GxnWmKv$GxYHz}2*pJZcNSpwZJpr}BiBtsz#&TBB?=!;utG!MaE@#H=|=k{=(C=M3%%WT;@iI#E95!z#^UM%F78y0u_I zkwdxaByg9Pz@=zfrw8|?g5NrQqOEhX=<=KA6uj}&sjOlray)Q6q1>G6P^UqJZbu1F zMmwHPT@?ZmX~&q|XNX+3|V7=%oS zE(VRKE)k14JZFaJQjjr3Wh*w9kvDH_E+;i(BF_iJ$*SS#DEs3qk9n|o{{fuB`Zu@s zucmhmEZr+EUjgyP<=U9XiCjUxH1<&qk8ei$sq66erp?|&G=wIs;@W?iuFZTx5DIn3#j1rttdQoo3QA~dG*vb8BlE8 zr2nMu=B9yq?2uq_?6CXK?NZ6fc}X!f)TZu`PjpARld703>Mq=u?ro@B#Oyup#{2k0 zj8&DA=e449_fz+P!1Zg^L{C!pf(ygReJDKjM_ebEl|iBltNZb(Skz}?cS{SGVzW?F zST;2%>H&OKx3F%a2jw2`CN|4*?jgK8Ikj~j#wQh82aoS=)2AQ%sYgJD=6Mu_rydg? z-8_r#ps99)Z;>=!~X(%L`_*;u&tQ_q49zCK4W&j(^$#~l+5J*aX>7PmF37ofw$<3*~g zJ{~WL2*$(l+qR^Y>SgdEY_Fj3)Sqa89X5$WM%Z-BUIh_i_8Mip9>^$5N>&a-UxtBs z{e}?goOqM$)yLp15y2Q#=pS!`0FJ(c!c*^3i|wcwpW!IBUPuo-7*im=w~V_?D#b?i87dIxzoPKe-*Ao2hbxbf z{{~ya#&&#>bZo-=sUJZCTmOT?Q$OJvw3P0O|COq`ML{bQeO;fa&BbXl^{Jon zLER##$4ZquQa7%kei5F&8-1_JnwN5M9CogCRd(^Cq-LG4M! zF0Ntax2^bnngKe3)7gV@I(x8z9tJ1Iyt;*<1W6>LQ@0+Tq`6E!{|~qEX}`Huz=wY7 zH++VG{f@#@^C9130h^yyR{N+0P*b;rA2=L~Zk?B2) zh5w78@YLeCMm1k0rXMJmaQfGCospoH0FO!ZCCP5ZDlHW z`l+SyF-%+rg{PLK4i0qkm>>B?N9Q*Ew_#>%Gd^WKkGv5mS$_v=j%b@R{r*ovWN$E* z&vhQBmq%u!FkWYp#74&;T%h+2>{H9h$GUedPvdd~U}SW&q*fp!hulR&uhfdDMp~?d z!c!}ghMrqA+C+&Bc3h_SuR{7&Lwb2k=R69LS`BJKBXpb&l7x|kdRa2j1ZQ=zCm4Fd z%?GQdHKfq}CEUtr6KdYMG%@^%q7Cgnim)=oqWD zrA~&Ty1uA0dyjR*7sqpH6XTj%7hDEg>tlwH^-vY>E%=LVcx-k{KeawSL|@qeg{L;e zRd?qyTS+JB0M=Sbss>6;-9j>hsEu%6mS_}YfNGzie-WcLMolrTJ9B)JgfrG{BDYNB z3Xe7DMZ2jQ2uFVygu+vUag7dE;&m`0E^1<;Hr2Hp3<2L^NW_01Ass?dLldI*ljP;N z7v}OIQm11$j0{!`?a-*rD?&hOC(;fNXni0ibTa_zY!qr|GFW3o%33Bw=yoCXOqk+& z7L9cJSO)YDusI3L93_!JRU=@7pES`4Ck)1}pz+jhv{nL_3`Q{N*}>SI40(gG2dNnh z85Im97x~e3eo!tJtAV9w#n(Ndq5>>eHUQjSAo0{l+TwE6g5E}vfrwlAdTCF*cOq@& z8-y|h*hYh?Oju3sQh}RV>M^j{-gx7wF|1-gUb8~n;=q|WsrzcMU@Keb*gllVc2i?< zUwXEoET~wS$d}_!1EyrE8V4chfBT~FR2{CBv9JA%zF88Q zR7$p!O>EVp(X-n4@g!^r2we}TNNEIvOQm^fAyE^kqIxeI!Kb}+JUS!IGSvibgrkVU zQxj=|9S-qchr<9)lSo(!2+Pa|t}@d6vrwjH@>K6%8GPEmia9wMBygeyg{P)akL`rm zteu#x+q9L0Z3)6O4=lW>oeb4`&_OC$LWA@iO|D}STtV|`q^E3QJjV*L#(2tei0&K*5&jPDcv^6RZGm2R zo=81DepCKg#!0gk(Yufkjw$yBiIKlfn-__RO~^hLBOTXZF%nRdODD3lg?Qv@Z~YCQ7LH?@DiXhJBM?~V7X@R9PGt%Y_2(1L@bR9RG){!Q-7c& z$!b1!?f(J^5uf!u8ZHW#lRDjO=hLDbzQy5>3&_X@v!D%iA*#_{Gf{ZzBGS-Zi$>4y z5)gD>1Akmh`b$Fkc?o}93N@h-@m-Q6jtS0XVowVEQCv;E8*ws6q(r5qD(F==(%26Jw4H{3F=W^!KCi z)GQhy-j+kdB@k%+a5Me@X&($|{mppjVJb555E-m4orz35OzN33Zw$pOpM_0Dnmhz0 zBplTyjO@`Lfo4BJD&Y~2f(8c?XrqKH8G>-?IbXu52ZzVWkT(QRkeVToKQSeEg!MO? zazYW2;0!D^iib}^umgp73M8I-nijYmv`~m=$k0m^;#mmMD1_Xlq7ctfk3k`x#~V+* zz$*6CRg%$)0}$e0e6MW*5HC`g1|VL-eW}p~AO=>Gkm_adqldkM0_PlXt&BaqYE;dV zw3nw~#@bxH1_C$i@H(gh*x?Pl@zk5FVst_jKo3k3zIZ4s*x@a5<`|e_OTo8AEXSo# zp?U|Eh{d}oJT;q=?d%d;^-yDAhxbVMen42*sG86l#39W=3vu{>(yMpyL-1(_t20V{ z1V#km&nP_gF}2%45TA7r4A}4&5`Gd8mYD_I45YbcfeoLMr+U{u1D|#+EeZdMPhtPx zPbq~Q$TljVniC5|)vo1au^-;ZF@ z_60b@e^3Pre?sA@|5B*kVq!+jLJMd3nOwglxPs6#iwHGyH3Bg#ifZIT9~7SIi))~k$u8yu`OrtK_tUqpeiMNh`ccYa2`On) ztOYSFP6o?0d(Cezcw_U*65#V8h9#+bsX#UV09OX0Ky8SUooVYZ{ghM zCsMptD?v!8BECzJMmMgnEZTw&7k+bO!vhsg514P%lj>8>Ijkb~Sj*&UH~*X<*MZrE z>XvG<_x}znYk0_Wi5l-cxJfs{2csannh$CTp#vP;0S<`+o5!y6^9gn#%irXwpz`wJr)zt%qy0my0(+$IjfCR<<#LAyAVAQl&P5+8uJxANN4vsXcM6j1BB%RL+u4 zvSLN2)JV{|A%an$3Lt{fc;l&BRxxJbj$Myx64ZEPEQnxla^@J-VoSL(B9?<%s8H>L zN`z!A3QvurWIN}?Ry{r$h+tn5)&+!4xG=RP3{;Tjs09`5M=jMmx+%nB~<(_FM5gG0zuy^Du}PrI0roAn@q8{<)U zs)3qpH^ge~#%v@xkb?;%Y)lZQ`CuUjO=PIvha&k5axjs)Ck48r$U!NO3dUP}Fl)JH zxn;g%X(}fa%BVm*CZoWk0dS43(8L79BMmv2LYCHmC5{}l@e@Y~;`X(JN!u472OX$_ zg$jkIIw{m{F)<@%p@kfDk*hnw6*ONGIhZQMy+aPBL4=PSOs54iYzy>q{V?j8_sD^) zW^y41sU6=(5Ty4S1VLhI(&=!y{Z03jBXI9257!`tw4+C|%1Q)vl(1zZ2og4<8N z&PEV~V^EE}I2MJcj>9!j%cK%>g1m4d2**>(2?;4_6S9RMoJa=CHG6+yFQ#MD&Pm|& z5riJ9J~>cb*a;1m3qio+7xm-w{oiK0uZD5`J~YAT}&($uC`Uo5vwp*e}Mx&-XVwM$WW>M~rTyEdVeOe za5*Jhk&xg(7Oo_N6&AbatE=SGyw8iklWwC=C%GEj&YK+<^I!2Zh#2gizGntUS#13H&R!HK-fdz$e7(XiCiYYoZ5IZ zBp?TFLE))eX@~e+4sDlkAPqt&;WpCV9?<$wLg-{FlyC@1w_~Uet1ygPhqRaAp(8w2^5}s z64%Ob!Ba-tEa?dTg9)O(sHZ{Wh6YoA=zO$BJoODqkmjR>61++U z)%*Aw__U9%hiN42Qm=y-p?CuY4tvl5I~3x%4ut^--Xh`K0b!ZBz_ojtcNReK4tc8g z?p^R{?DY!JYO_fUB1eQL2?5R0`7vysvO2R(bBQjKP|DVZcz=4mc z`!9j+C^+y*9uwOdTgh*@ZX1OFt~Hwmtw`I6wkw?f=IaNu7M z;e!L;(Sq-73-qe{2kM#k;DD@8a)AT!{_f)f(rFDYAmKEb^l!N}xWJFN_tbxI4YEi3 z_!FzF98muiwrpHLB4(8QEVoS82rlpos*w`EqVUxJa1GQlpTwLXC7igxZv7gzxIIFUg~lGFcZKVA@@_52ww0WH*Ep}fAuQG#JKA}$HlF|c7NvBrQ6OXJ>C%iyXzW|_g&L&CDGwTFb|SVOQu zT#AAX%cG_;*dQ5VhKd#BmYFyAgRfSEa3t_bDDdzRT%!Yy_!|s3nNY+kl(1?-f&+?J zjSN=MB2dKY@+p^@Id+rnJ`mBU)&O65H;g+z2(czAO3(TG%1xsn#9Fk$fDrxh##3vv zie1^Ym<-kW@WVP_)*ViQ67O&p{ID*yRB%25Kg29vPvkNss<&=^@S?>xK!Jyc&;s$Z z99k_QK%lRzb%4`&(+Y#2<2yv}b*YC69I9Ffxs?dDKj&NB*OOa_()h;Kt6 z(g83G1qsfvP`Ar93t-rc47~&xHir-mFvwjhz_11N7=U3*yz$gltYW|PzbEzM6o(eX zx%f`nf)=)>Bn>TWgZt6|8(P=^jgWO5A&j=#7R=~R+oAB(_PACC6?QOsW=WDS9&2Z{ zBR+M*2|Ix*fD?w}ji+{I6@wD)?)3m9QHuw`f)jQjXO00Vw$vLTVmbbV3e~QtL?CuU z;i=sz*-k34RgWqLPS}Hldj^Ds4RZ(G010W{SwO;G6kWY{Bf+P=tHL5R3S4l1GzuIB zp=#TG@m9NUAcVb1I3^%0v;DcuPxH%y5cVNY^?r>7pY|(}d*kpCjNcap9`Hf=w((-C zHhwlz7vRBuB-}qim}a>J9>`95PPP^Ykk5bz2U7Pzf$k`HaBv~ONz!C=!8u^K%@#6M1fl1qk8$L->6>$d(C!+Aw zBwV8wiWxBrE%2a3uI2<+(0obope)3_0}m!cgbyCH(1Izp1$q_TNV4QiI;w#UB#t7z{OtE|>nox+w48%V5-k}kPrqDEkYZd4-~ zrlRoFG+YC<%p@@4{*`m?2v$z|A0>_d5 z_>g|ie~@qjgoG;MI}mHjf1+q}Z22qfp{w~p!bxI}wHB^+L(i#^8~Q31W<5|E+sdCT zc9^aFDY(bq!oXE`mNJ8;yXk4HwK77T&Khpz#hK_<{tVPq-pWh6n(lk1+%jLP4XQc| ztVpV}QF!VcT%%oFya~E^=0^QoN;oee!Ld>Q0~xH4*xg&5FQ4-0XpTKt{12L30Os=g zSXlVG^$Sr^>hU*bTSa&4Giiv~tzU#Up1PP->|?G2qA}h6mi-b)&>cp?6YntAmiNNnz?Vkmeez4OS73{0Ur;3uz8n|RG&Dq%e@ZT{Y0s>gTEd$p1Of{+N;_y4B@n3 z?ci@DL*6jlL~4d%4|pRx_&ND|B(V?;EbSm(-VEW6z5Fd8!9fyQ;d0X2%il(ZUhd^@ zhY-D&m%G%x{2kO|_VRb)ji>Hn6?^S!X%UNW=*7eMUe?;s-%W9PLw^tMOFP&b`i-kg zO?59Mpts$J0)OoT*UG#4`;D?$(gl`D^F+-8iF<4R0H}hk{eyVpsfSp_7==4+Jy1yy zVY2vv6>NByN^^2CN9gvnX(kgZk}2h~GL8W|RLs310{Z%gh8W z%F~>)Hu*1-r+VjJ0-ts+Jr!TZ=kVYa6nLBlmDnDL!PKAPXFyZDi~_+3CNF3dCbJ3QxUHm!ud~REy7ujD>&%EF1%c>;TPCwS${q4SVS+m`jXqrU& zQf|$5|0~>k>hHJ)O`~1>npIW`sDB7s_I6(aW|aI>Zker-?fy5YMn-&#!c+gkHBifR z5_5u#aBla%qm=IxQqrbdYrFpg87$ZA{eZm?j?FLs2A{v(|B$x*r z`B{L#PqZk9Z*f52zhq>CS(|=sU0{JSFfu z)PzRFcR&_oFdv?G?Sc&E{uk9Lrv&DQA-w?=I299AsCIF<05r#tg$2bJgDfnBdrvKl ztL~R&##WCAi?G&8Eww0Xh%AUlQDmVHYAPcOk|1WJ=nFzUQq29>t9}rU{9OzM{(KCs z(eXz74aS>H>|qH?STZ5Ofjulm1}kXxSfiGfPxC(CP_@^$3~N_yU2TnREovFCme<2V z$44HPMMdc(e?z%b6nR*VW*FpQdA#w|3anyhuJB8ca4l(T_Hl<5!LNIrgeKnWEZkuw zDyk3yd$=7LGkRr_%Modg3|s~5X!=!Acxp8oA>Nil!zB=C{Sb9nowRENv_9$(dYFnj ztVxEv+wHYTJyW(^PCO+N_yBW|aOA-pY;M_$_lIUbK`J2*YlFs9>(EAfbsdHvoOdk5 zVO=uh4Z(V(W(aomcb)B{hK(`Fo%7s4q(clW9VsrZ56KR=VFQrh_y|pKd1%261IW-z zxM3iKXt+V{QsIV;sK>w!8{>_qHenUJ>Z&Q>ilYtUV0?RRp$#>ZrqPB$xGx=PqYbXd z=0t+727@1cY*Q4T8iH$OtYN58HA@nI=@d8AFi^OmhRr|~KniWgd+mNGP8i2 zfi%}Fm|<7)RPWku;M1<9X5sGm7!K@#0uSb(4%-2-S358pi42rsFA|PS5T;pgp$wzQ zP`&k|$!Ac8TI$|A&>ck?#^h1KNQ)0rgZZR<vI@zEGDH>>=1*Eme>E6`#L}cuqud&d zp$Ye%D&iWXj&^V&tE>c2lY}iBV~}teB_+9Ku0}A1W>g~|$|yWF8P`B9lS#}8^1+EQ zv{1^Fgp{;N*1{NC$zZu=ulwyqZ){>|1D}sEv{Q9Qpt>O6&g6PRL4#@!w+jAK3Wh6d zi8WqNkK&!49>Z0gg(fKK&f!HIP3R;eo5n&4R2QnzGTkUVHI+2dQu+Glsf1AI(}TS=2GCAwD4fMDc-RQBxTokR~_1 z{5ZK~D)lDD>UfAj?wx?bQzzmY9Tmj0U{uIN0#2fYo`eJk5^ypZtnk<)f;vS$Eyxo% z+#9S9kJ*beu150m< z%a=ow14g(4Bsk4NlUyEKFv3-2=p~GBHH2swLGDsvglnkBzzEmkji;_-6}$J^mBSZD z6U5K>4%$K!uBT9qCftDg(%Uwg-~hNPG=jPjg3v2(LgA^Kajgt1++uXjlCH8+Ww+F= zAatV(w}C1^7jDNJPu;;PhArIe>(Nc(8jp>IF5F4Z9HU!o5qOt~<=_@7RCl8iF}VkY zr|zX>JMF|)Jxm#N;XV@nF(Bk)ajGBE4a|_{sRc9KPc_whItzT-Q^&(-DrCwa^#CLw zEDxf2}hee{G!(#A;he`NIKv-s8aAT0>qlGs-N}lR{d<=Zr$E@^x98~b*2^4t1 z2UXdAh}qhY*+_K24o{Kr=>%b#6Bg|73>m6-;#u+;*x@A0g&khVqk;h!AIu`} zMY(0l8`$9`R3IKNqwv%#xJH+2Vgllk20Q$TEUyMEaoFKCe&Ps0+`iYrr0ok}hc{3K z3*SWHskbQ9ZZR<%52be zxnAIBa3K}I%-jXV4k)o77#P2+g7msU)Wmm17T)lKXmsEW6}}R!_6dpq7E7%4 zceOYJXHVh`bGX#|5eCEnhyRF825|TZ_xQs#xav++W)OAv{h75^mZ)D?L%=~CivkY6 zqNXz7AZ=~B_5b9SIW#9hR=n(yXOEJnp+#xjQXNdZAwP!VvAZB?ByZoJ3hv+2r5c5{q5nHD8{fTO)(fl zAH2ceoM9DvpX1E^goJh+Q>fPH0 zeA>NA3ArsO;KOz(@Z1inv3(GewGXqA*1!sOAmNS)!ZZggtY9ZHRPVrW@)@jPXX@T1 z&>h7JM&wb!V2clCeYUIIGRX~Aup256kKIvtY7bna2`(le9%)#?o@Ci8V2NV|Bl(FV z1abRDfl1pJU2<<#M7kG{&H(zf&%V6bpWnG`e-K)WR;Z! z>L6juh6yBOM#;f)%Y2Q%1c#s+IdLcoPu1fZsAWQlIYCZ1VS@3L(vXmnHuYLC!2~i` zuGxD9dx0FAXBxrh!vsxKT?|wgc1C0Ej4x(7x9Oj~S?0!q`wIVzLb&o8ujfheOV5+x zdd~t1CQ@q-`{O{tBr>v5Y@ncoYP3l+3Qv_u!|B_i(RPW`Ay6=x^erL1U|YTLT}^?g zP*Hq`V?hP2qSFBtRM?pVD#&VpltT$^VwJVHt`;od)Jd?Q`bAwkbjNUl4l&2z1Pb@~ zGc~yCUQ}iTb^q;Rt(7FIn>EA<#HT1uFcmeGaRO;-)32w=EmLUDBCMuE0J3cc3Qrw| zYjgwu@}0&3AYD-+Xx>wI3A*OuabbpdzFP7oIsrw z0%H%0BV+cTC~}z+y|wiuNJ4J(pzzemv`1o44ty4A)PssZ@y zhESJ66nf}oC_HsJu9abiD~#4z(rs4Ba!p+cQa9Le6{rHR;cC3`)HSSP@NgFa8zj2% z_*h`WwdBk(+Qk-u*NIpTcA-LbJ?;^e8&G)aMqHzFn%JrbEdw^(M8cZ`Lf4;eiQqkU zdl<|i%~uO^xP^+U_w`orXNdzgXl_S=QzbOS?w1k?9U22Y+)2W_0>UzL zgPVgiFD>ZdZt_&`1z<;2KSOF#+*N z10bFx%TobM9DsP5pEyDgx9=G+Y5M{I;#pL|!sk$U>Uj#aTTIM|S!e+eFOciS1Xs{} zNdV#{A?_Uj@iIjC0K_Y_;7_&%dTswI^~`$!Le@G}0}%G`J40jEYiNd$to)s)LX)qjYCM}jFPwImT4QoA>KhXQsZ3|o|=topq6Fdp8AY5oY^fJy^#^8Lmc9-r2kt;-&-8wbBGER#dk~= z4)KNP{J+8>z7(shb$PWo1m{uW5Ociv`wAw+;E2DARR)gu8u$3aIJoN0RAwM`H~uGU ztz1#xu!eAixE6&YzC}%CI6_+7bnk!3Ei-8j;fU`b07>^f3QzrjYjhwGpMrrP6OQ;d zCH$C>;D96kLk24__8_2sl23C!D`A3aZkklAZ!9&mw&Kvjf5BQ_97_=&gZLR0rTzSE z18^pyWAlZQ-EC~{vUZDvt4=oH~X)^Q@Ls$kvG=?B| zsTjht)MGG&<$q=4zLF;*weN^FRJ&Vo_UW0$SNck4iK4e{msAhSF`z-Sei5%DYs_xKMMDr8jWj^ zI@-ZnR#^$4_7=A6&A)`pC>bNS%+<)|e;-sMAI75a)HqxNwM-^4C&&lq=6_#GsY^&n zn`Euc|9)h!T(j5x_M$g7vFr~%fAcR#`Eht7P@VtJFPKe&e*(cQtH$f)x_G3g#Be2N zZTkD_;Rp@P?{ z0YbFvq9VRiu{Qh@M4My7U->Tuq^nOka?mJNSWD$7H6*t(6q2nKj(si$Br*eHk^C_xIAYrUy@!Tc%94aaAo~MP5xo z;i*df1a9qqlTZ^)HfBUHa8YkC%DV& zqL=ua`z}a>|#{9{NxQ-(R$S8Ivz2fKU;${Zw*?1GPlem_|%ZS;==ji-*MrS@_u3`96R zSR4Hl$dES>Cz6_h*bDB+0RlQ)?Sl>CQ5sk}S^PW+;vKvF9+2R$3GHyXY3=q;Aww^B z`=>&P-tEg>>Tdru>M^_h)A7brXRwNWclFem#rON-VtkKl?f1{5JhqrR3-_gy?frg* zaW@7*g~Nk78zRu>&Oza+b8)S_Y^q&u^VAFpA-gxRlRxwQB z9$XJt632KztWEz+a^@JYVr#RDL@dXvP@%dQl?cZrC_Hs3CEIBxw(9Z6Z2B)F;pG7# z|D0~t4-w+2Z}$CZK3e1YL1aRRd6nIDnwb(9*#oC40NNF4bxP^qb zCJ58)w>JN`k)e9~ZzrGG{NF*{cLutnoBzA=s9>zc2eTZzTW*=*X7hg!DiDu*QF!V; zT%(IDF#+*N+x-8LEcXX2@y-7%e&Ps0+`b3Er0okf{|}-H7CwZ+Qx8+9-C|-!%tCAP z{|LDrO>hOxm)!h6Cd9ql{67v6{^tJ)TJWT8fnISxMLqL=^Dpa@DmMS&MBwlLrPG@I zzl76d($jKl_W#e|-c!%w8f1_5@i|smIiQ{ww(R}CM9e68L2j9@k^TRRs76Y>gu+uV z;~J=CK8ZO&N;vobuTaXL5>nD8U2FgUDj6)-?A?LAD2~lBuYu3s|G!SvZv?96;h4o!_;knpgtb~j>J`U2Nz#}|)+j-Lq$d`SskB_uc?fxnZ%3X9$8)z|WAVM}z29J{*imdW*<#nz_! zhW7TB=EjDu=C)S#4@f9)h>qjK0{=us=~REG*B*rhzM(Y+7Wfu#@W*Lb#jYoIWGy?> z4Dg|W?;u8ZBnec!BU#YE_taM*AoeIYGG_Y^BA1EK8$16EDaeN(QF!VHJn%CatbUvc5Bx&vnKA;(h*oto1Q0wK|kD=+HJ_7!q^-@25Bvz7K0e{#l=y0Y6)B`!v;$ljkBbKtXR<} zwG`;w(81E63ZR2!@WxZivWg)Kck+5blbFT>V?hVYku%4D7F*UWFJd{Kg$mUQs6e*lHp!!c@fIJNar~dUMFz_?dsksE zqGNN;Nbvbk!YHa99jGphfS0+RXJG9={Nn`HnrytDHN`VMYle$K3r?t|-W(pp;e@@( z$Y#NM(l=O*K{Z-s9~7P%OB(5{NjO2=4&j7xq~ABBmmk1nKheP9y{dyS9Rg7m-w9ce z!hWLF0Vz~CxG#ThAzTHgG(yS|gZ;%CYxP|%tiWlMu)-WI_6krRgBA`Diwv}IAnx&3 zZE)4ysmw6yj(jj{tz1!uu!hirxFxdZYoAfW<)%6m?ne#zO?s zt^tLoCg2(!48*HoFvx@#8Y!VEA;AGJ6v<$P#vTaNMENxDiGyy{*%f&P;v{gFe(`aI zlDyl--x^Mj;tI_)!{7>Kyulx&VHNwJ>#O{@W*<{%fe77`Bs%e)WMK+ZsH;L0?BQ@^ z%$pK8`~jAb^SD7=fb6TMLcgCZm2iYBpG^%9~=cC8b6S`RQ%v* z>M{7iF?i#tV_C(%>mN6W#w?BP(pvV|QSM|m1MI3D+a@g;K}UOPv4_=yNBc z@YG4TR>lo_jJ8?Q5&SQBqrRwLGdP`` zIR>oQ`t1x6%ke5ysLn(s!f_S~Pn}K4cAAN;di*h%!8s&6Hz0H#H;6ZY!3)xSwD5xS zsGxcu{{TMiqwBaq!Y*|_coB*VP~bEO4X{HYp6gH;tY9VyFA50D%muFF)4a2=f{V#h zy?2*@PkUD(8!rU`T(}Gc9=Aa)whLmhc40PB8aTlfB)l>~m}b9)6I?}x>g~Upd++~zti=bjCc9p4nc)T}xB(T2$BigFbrY`96_%KQc%|8<@0x0Zwo`s$k(AC_Hs1h1xA9X2dMCaDuzYb$5a*Xuc#)aE}o84kx%5 zB7B_SK3ecc+XB7pzMp#LJx-AOxIw(X`xt?AT7wZtI87$al3RljJb-&oJ&0?NJ=({I zSY_padRW-9F#?I0QSyk~GF@>KVg!%k9a7>k6rOq<*FY`vNz4gS!if<)K`Borq@+!{ z7Dn(C87$ZAt%1ELj?FPogU`nZo}ubz1J!f&Sp(vio+HC$o`n!RN3A*Rk0S)nlaY;L zBLpv?8g23-3QxU68tJAOBZRvb~SOQy<_O9RS3qU;xO(1wN#N zj}j6bxWJ#uU_?oo;2xxt1AapVn8u%v}tlpam4SYlD znKJe{pn+ugtAqv;0%XhlE%f`zQVAOP7ic{79WAvNQ(+*&Im3bmz9&Q8K>R>z2EsrC zyCB*3N3M_7sh$rSNH{sLR3m==8{!?%z>groF%;V2a?^qaej-CJp@IKGh=vB_E)^R1 znR*N~@C)8}>Q`2=?;2luBqFbVhY0k!`TB~j z^W$0>8dw0IindwO5zJ;R=8IYoG;U~MAy5U-z`}UrsYO`DFoipHJzz;3;{matfknxg zW59|n+xmb{k5{2W)fbfrM?VyvT8xtIG!t9(_+y}f#YwnCKc-&!d8|79Y%_Y;C#ajBKERbx?tLtc$`^>){$*WQhrgM;bJ+K3O&hSmMyY zhWx}4g1CJHz@+U9pn-v?f`uEQ@YKc>YPXn}5wp;O1~wsAO@b?Ez9cj-NQip}4Ge|| z9~#({77Vd1(ChA@)bsxjG?3`;J~SYm)<6RiPLoN)9AfJ4)F;Ati0nwV;6= z$Y8l`wYULi+s?p6r7Ka~v17C)DWRh!OGKkOe91CH6QVh1!ac!kikIau{Kx*lDfPtA!gl z8Rvl;5+j2e1=TUQVYFCd;D%b<<8RmCsyk+x!PP^;7}i?3rS@SB;RbOj3O9^JO=Y-2 zGQQexQSlcLIAJ!Sxuv;lh8#7+Ll6&wz|!YFG;y%J>+A0} zd!o?9A+*du6Nlmr{yq(>*ull76ll#q(wxT_AFUVK|}I{0LDbpP6}v!03-A}6~HKw!5R-T0gPr+ z&y-PkkGarD0j4qcvQW1FWmxGaUL}}gGH5*2LVxUqVHmD(j3mxkHs$d0{Fel-J9 z(Z>%%;iJ*4Wz)nShBQmtf4w%G82h0F1r<3rEfUwMr;bth! zVGC$ElRVWsd=~h$!@0BgY_Pzob5P(3C)8^@B|d1UW}|ZedO44Te@GCfd1OH^=aZp& zk1imefnF}8?wNt^DD-ks9uO7t1YshJju#K?UM*DGEi9;_}@)Ji0;`UtyCT(8;y%|WaOVvcB@Onam14wy;3|4sTaYDT*pYnWG6+lXR zTW7O8Mj{TPyai$9zUXc~j`B7tO5^

    {(G9Iz}9htrWUH$D)#Oq01}@`n(Jg!u@Cr~XW{BqHU|6$ut{ zCd5xZChcDWS|2|NeNM$sJ|TlO24vzVpOSi}jHV-c**F1qA|dO2;t5pn8LaaYtrBkX zSI~IsZ}h`n)rDaS=O_y|`J4=S!}JBI8Kz0_&f4COG2JFIP3Al-;$xT<(tTiQhy>wF z=yu>GUx5VYifE)O1{PlOH5qz|m;3`lG+rWisd&jhsmI_Y-{6g>zGW2$1^EjCu7Jj| z5^*@b>$k9ye^I)|O1{H=X^4%LIQ~v;u!^nFEb4nmL|^^^g{S_FYh|3|N27d}bg=$8 z9991ThZ`gL2~+__@?X61)X%J9L_^3zkCGDdc(g2xUT=EGg55TqnyD==IbYf^W&4PO4?*@VIo7xV7X@R zb?ilaYOk_(kvT1BgWGhsoWwu7) zsclFj36aD^#Ptvp*_QO%h4jOb!@b8uwueBy)(~~^9hrrR>>!%|Z!wV_#Ug8=Uo9rW zd6t++Zx@a`!IBsrGF*%^c*xGU$6qMIRrj(oqpJJ&2-aHZqjqHt@euJaiihlmn#y>H zB!TJoyUQ(;t5$WGvp`j}5Vk-8Ap=F=2&| zf$R%ey2nY#;yup7Ku0t)=aA{r!7D2Gl+fRG^} z`f(s>4+>~~^ds~(75zAv3|4Q?L_ZE8^-LKzcgVS(Pc}$^dq|jilVGyhKNJ@E2~`R4 zs0WRw#?yAQ2;giSh9;bWEX1RM40%H{fz%AmLGa7kppQkzkaL;U{V>MIIuh|4SlUq> zZ-hPv%FzT896q99F2605VPW5RG!kT`I~^q8@{CG~cox+!eax%GP8pNSely_j&U4$s(15v@M$+4d3pi};mV09@Gu!_vt1F( zwJWoc^gu9rNO*FBFwGAO!8nBs)%$TO`3!<_8g-u@=#C;7XXH`An2Qf)EqJEfGWQLF zaTY2NkF!yD>Kt67t2!|O@km23&Lzuv0ZSag_ya$2gdlF;`C!ua1qj9ksDgzTqVUvA z3bk8I%!pZNAs82t>*54g(0oY*;}Rk69fENwMED5CWwhXO+XB7Zzk+(^J%S;to~jUx z#PscB7t)Ijb|G;!DRrgX8tmdK+y&R)YRD;d*SVs8^JEF zM>TTe1{9vU5!XO16HCkqa>I#T+(aoiC#0lJ)E0Je3mGie?0t#7_>N6Ow}Q{dE^edh z+XL1AXTPoypY;?Qt|u)-;|^Ms!?!r1aVHtsU^b$07pl=-ccbvsJ*1JooJ2GvAR(f0 zFX`_K>F4FIYyJo|di^0r#CKg5&T+rkggtbA$K{qO zIQLsYJptj!M2~KBaiqSj69iW$kUYYOhSSK4SALfR?zHGM?EK>5&*4Yv)b8S zEH>4*tG4!rN&2@o_<>D>|3jPSA+o$FI;)S2ynu?*1^!0%iYPMjBF!_%$V+&GKf}Z- zc6T{!nCFYNOpAP!FZt0I?)G*=CO4Puc(ucPqP z8#GR$Qw|-Hz#)r5#NVEcFwx5|T0-G@g2oKH2NWFl6D(XCW!?lOb=&J|Hzirr@K6q>PhJH74v+Bcw}> zo`WCVWcG!DrAs9qAHoa=!157Da5{F_gfLm z5j9k({)I|J=sOgi`ks>Q3>91TU}zwiA4vG`fRLvldp)ffI3~?;3y%4bTB~>bKj71j z=RI_o+3yFbpCAxH`!5Qd5296e&?H7WXa<`3g@nHbgk@$8cS~t5ThPq^$Wy(`zkyG? zoIjO+2M@fOZ!z&|eq5ugD{(@5H5*+7D9r*STrfeH=8}cdEJTLtU0RrY2Bleqx)%*} zM^TzSc~mg`;)7Ya_LW<94};S5Lj~fo7z$4i()I-?%`&Khh0CJw)N&MR=b@Mpv(Q3mmM7N=39g{|k|@oJLfku)W+jO5QJR%$ z!78=|dULWW^~`&eW-ko$RiQMQr;i+|T4b(Ep#GD{coQTbOl(K$8O4@X9AvPP3 z!E(*sJJ}n7*sQf7_096kRR2K?pz+At;u{K!TUtvL9Z1I1Ile$tIujgX%R?o%Z ziq*nuHli&#yozHr85n zgNUdhP!Ot*@A@p1W~f-=Kxry$>+lPm>P<_*XNHNb)>fige1=mr@tL`^6x|H=#ITyp z#YBVEY=L|H1uR^3-z+oMdN|yQwN{d;tyx2?M*NIoHQS)3GFBt0Vn&N?<(4TpH`_vO z2eHWE?NNAY2VA40jd&W2Hkl~Rj+C%dLV^RO8BPW(T=qz#c9u`8{SD95VoO`2e*Q`1 zK`6UGSm}EooEahSHt_exH$=giU1^m8XLiFI{9!9rv47`Xm{u^vhh_GFMBPCpcJU5s z!7_VNb%hw&qw&a?8+(ad=FD6&c_aiPTSlSq)M%O|5h;hRNU)GFAs|yr+Pwo>ACL)s zP6cGfkii-fG69)=NIg?_gK``-&laar;{;HQgsciErh+^H9mc{sKhY|IFylbuseS2( zy(|pF6i#Ut2vbLfykXjp)C|)kcxQny`~piAC!m=&5uH9#Wz@&pu~YQ(iN+|p!}&yo(-KZm2L2o5*WG7(e((lQBeJXK;9 zBN_r9dX$uq$D?H-EzRW2F-pePtYs0)K{8aRCZiI;X+hzsDU@tyq}ZxQIfJyclCUix z%>4tN3aw)>mNb_wjHR9Ws&}~qeA?x_hZ-xHsT4#ZP@O1nQi=B1fs(lBKpAwUn}kyX z!ZI_3JDW6TEp%lXd8&7II{37+xiWVK$l=goDDeCr>a-ma`?W)}(HQ`&96>@aL73)^ z1*{xNhU&dJihKrGIhwkU33Nw+m1Fa$VC2OIv&=kBZrK|QuyQ;q5RVg3cZ=3Q^WXvk!}X>G zpN-@TWv)lzsT)WmeK&dBMO+Udlp9HZQ%FA?Ih+llxSu34 zUfm3VdaWVq;yW@6GPy-GJ0O$Z{FEdGBDqy8vKIQ)LL{7LtNH;?g>J5HgC#L=S6cd^z=A9Xit2#$z{QE=oQ)KmsXBneEvzgKRVT)m09x({NI zjekVpsrzw_juYZpFivEGA+spqfrJDH81f()tnk=lgnCFmEyyEj@@z{xyM_)MVu5q@ zEp45hGR)(Vun$90c_{js4~9H~iqggY9`%kW81g8sGGNGKc!R&-#VYnx=Oc154DpeW zCm>GuI|*F8-&sh=lhj)wK=vRyGUmfmB9{p=H|%{H(vT<5pzzeQv`J!74*ifYAyq;c zMb!Hchras(3Qv8AYh~EuBcpkibf`6*KB_;1 z-VJ(u45|S1_zT{6>JwHmlpzM82SkZ=JWv+s@hLfT42ZE+!{S}o6&EHUX z>T^oAQ&DWyW10ayz98Y30byb5UJN=0@ksO6LOi~rvg-Z)JNUG}y|Ph#4LJzWKTzOQ z5RI`zBoWaeGH}N?B>XlYEHg*A>qzs|f;;|2p6WgQ4t(0v92xsPh~dr;DDV&;YP8)E z>$N+x(FFi@{7Az8BnZ=dvA~X>$WXm6|0SORJAS6_Ujp4xu;bS}Dj0Y1!7Lm9C%5bc z2JH9^6^O_0C_FXa;_(Hbn1FbsfgSUM*i#DxEOD@7L4M*0LEOHDz@+U9z>bAc1q&BJ z;i*L_)NU~`BW9rmcJv`v-vn3Cd`YmQpAh#B>{tvUe6VA2TCjv|f!-M`Nj>u(?2vU) zKCmNW67i7^>C6V{kkFc}T1svW(y=t|J++KD7d)oHYcqHJ|F2= zovPOeR2TO9f6QG4m>fm7#ogWA7I$}t5L^}wfh^}VjuI4P?cyUr_QjD(h818U^NM}y>|YlX;lr4iNRN(`^TCV= z5a|%hJRmYZ`uMRkTssQpbE4!861pHVL z+-|u^SmNcTz>k%vriJ@@U+oo{yt2q;GIYbdRltl%UlolttI-7Uw3(VMLBPDHSjXz5 zT_eyYSV!t#A=a@b8Psxai*>9;>S3~JE?Oh#0otgaC{oF<4XsIHv_dl00gW~5(ms7Q zOWjW&F$&38j|^4aU!T-;e>J!-NCt9i4VTgtzj;+9V@G3FajzGomH-tSfCTUUP<@$q z3aHqS3_S!YHi8fbR7kH7sMwf#JW#O-ZmijqLtLKI}ci0A00e9FIH`Z*&Ax0*J z0o-0Bp^M|7aEI;5Sz#}V&UibBSZ+nBLemF>2*r+Qtm#Y1IhSH~o?3)m2VUD4nT80yvm5Pw|&JgU&2gv~(MWCrkr zU*woV6?P*}ea8lX&pB3*f4k#Dm_HB=zA%RxwE1GKGk*jU7%0LXB-}GcSY*3G5eymX z+di0l9z_^J-9v-!EQ+vK6%~xL_~6f4drOx&?NNk%Fo1aMi^iJ$aLt~R#012n2u0YR zEC&RZ7)7xBq$C8feFuWc*%wfRgD?aO4@P6nArz`-Ow5QZR4Brs7%J<)T0P;;;4ios7Gu98pvAppn*ivC($v|^`ODA=v#9f zt|4)pd&hG~O}{xo*xG{z5-hLeMCme9GoZmq7)CanjK-Q%a1CmiN@7mPhEmYrR7yE5 zC#C4Ysz8I&$)H@*XM26PjUFgxfG+_J&ZO$If@;2mR|z!mr9grc_+ylZ2E-%xC``|7 z3K}?@`YKo+Lj%Le$m!6~z&RMkY@Cb6n)65_YcmfGh`T8?a6aiTNa^L9D%wK>Exa}t zLWnyBh>Ex(Q2@Y2qOAk~Sg`on3;>{5eLQ+mWQFH6`a*nE$FjsJdRlRtVt?IADNb9OzCf2XttE9_>S+HhQ&DCH< zR$YU}nrm^*u5s}utns$B`*oCXeNIA2?S2CpR7mvtHaE(ror}S#inaT|t|5K;b?w!E z=Pq*-c$?#5g(T(s%@}BGl2mCAWXtzkXooM~Z^aFM<%&aGV`4$sK{8dHRPeV$fLkvT zoOr#c3jPjiY7qpz$@Pk?zEk9K;=5D3AbY5q}S9?+vs` z5udtPSj68)2DMn*7V-C!dYEi)OVkT}sN=hpG*at60NqKFv?}Ev1dTNh(Mo+lN`sI- z5>zSwFd3=_;So|Z2m;pmQhvj(A!{Pa7W`%gg6}>nZSF)<2e}>XrMgJ`N zjk|P3FMriheM2zMK>*g-^JuJj0oT?={fl1La7q5j3g+Fs1d8&q{$)^wvi=p^So11} z7@)Mub{mvLFb;+)>t7>hg$*h?g}p9fxj&@}%?J!47;m7l=1of02`09>9mkjTZ;|lr zK-jrJt>F90zQ{vW*}p^a^*wwSe9ps~R+;y}i7>p625)*$y$*wT?ZV)T`wvO@Q6OwG z4|ozU@=X=@ACsrPZ=ZnA`Bs>RpWFAH^O2gF|IzzC!=%KI-!_+^f;$a+=Y ze?^A+)_+YtU*3O1-QNb?+4BCoDk>Oh@xdRuzLzd@+n4u0U;y#>5sfuJ;hH^4i3x~D zQF;F}S$+vDae4nMKPd@8Y~OESa`uJt{&x()!avYh^CyMs851)i3srgl7rFk>eH05LtJw9z%vgz0v#w`L@M4rfZjegLZEIDL3QuX7|4R z2R8r0eVw9#yhHk$UAuBt&V2KM|!&oRd=Ypj8$ABxF#o z=?Xv}exqm0q~J>`{K=?#@}Qc(C0?n*$1J&eA*u1hdBIot;+1E(5{_Emlx&&~7@2k#x6-c_jtDGUx;@2qJLrB;AfmT#3ff! zQb($jqJL2ca7#ym6E7WA^e;wDErOu;yU^e;`?Wddzd^rtQs7X8bTL9N-gMgMZ79wxh8NzosNzGl%Mu}eX`Jai{X(yHiR z0W{XENGtWRDGfsUgiuBQN@S=Sgq2CnAo!wxO{Dnd$nZ@h!K)Shk%JwL*Tu(GAiAXJ zUlk;Hn}ar#xu}Z%)ydGqqJIqtaYeuM3XA?VsmB-nYvIP4wK>G~>WltNyyBu?9E|H+ zRrIezX|CvB7yZWTHH!Wy>SjF%z&cwWjWxY+ZC&(l;B^g`X z|3AIe@Yda%`k{yY>vj7Eht$hnAqxe z9AETrNy4oHVOh~11>YC_MINf6zmwwYd$=|DoQEYve{7Z62Al}PwrKF01=Z^?h}SL* zzUbecggXSnCi8%Y^CI6=(cgzW^?lnBe9pJRJnV~);lNI4@a-Vfp&bx=odY9~$|(B# zk+3UASY*8_`gb8ied~86pD+3w)ZIVm&KCX6Dk>Oh@xdRwc9Sl1+ZX)ejS zxMq)1Vglk(RP+xb%N~IxF8cT6CnX_>?K5C<_JyK# z*WNjQ}h`u!k;Tm$sd3Z2~R0fzsgspwiFY)q94wWvGHB8tyzr}lPs6+Fr3yS+Q!~%6ju3Oymu~?Til{T??rQ!6*2ecqL4Ud2&7Rb1&u0tzD`IW!y0T z1x0x&|2U{ZDgOj+ta*|{j89rwyS+&Q7{@}D@=uYo!rl}ex1JWU+?rB_<{1nk7|)`y z<~d5%`6afx-Nu*l&y(AsyFd_)A zpuvk3)UJadKD!|JLjE-pz8(mh%mN;`i(FHM{0Q>YckK=EIoAra@J)OS2i`)1@4KK5 z?SRC@SPXC(9RsB`)N@K|i0%6dOwPVg$bXF?SojSZ zYrdsWJ!4`MGrpRM!Rns;A~>!}RP8>A=qRb(=O{i4p?23w z3##@>MYlQ(*R9(53}n?_?>IIY^hQPdSP)+_R#fk2y->#2u@<@$nTP|LGzxxNsohsowuQm#jVuUW2Vxuup}7@Cs= zX;rQ-0vc-;rH%T~lZGJO?p3+I7#XUDU~y721Z!eTM7h4!?nA@-VAZPita}}ey~V>N zAh@JjUlJsE8-o^oh~SFEpyeq-+%#dFhQp311uvRjaQ>&I%h-bfj8a#ByIs6`FN0h*+$P#+vmgS!b8n z>b4qRtFKSOUV*TzR?mjs*Xl(Ms#<*mO0Vx=Z}2$>OKSDVD6=6L5rmD<;C%>c*Fg}U zT@ZY&z6l984TMc*0T0zhuBlpmGxF4TZFBHB*NT#G3w#Ruw?u=lgrEv-znJUnAAvMR zsV?6If!|BX5f&M*O7(5XP~Z4%$>&S;?WlYEpgUWt?@&br11&!Iqg5a2GO>NBz9R+@ zkG^QE*$LO|(Me1|Jc>&7oypQKu*9W$7e6TpL2TbHU~=|_Qhiqp!NLX_Yx+~Do-r{a zvQU-kO>*s);|kN4FVzPKanDNi-60|=)d$joLD~X$dftP2{{NKf*_ED@>atvYsV=ef zX|$(weW`BHw`MS|A$6RCLpY=ozzh|(_NBUn%PZMSy3Ex~slGRckq`Tzv1VUfgIXq& zm=p4$v{c`ZQufbDDSE`JQvCojDA)9XUmtj*=ZXbiQmP+F)dvODBk?_Z@yb0F)03Pk z+z+PC3f9Mk`ypiHl<30!Pz+;64nt$j;iQojnlIeN<+N}=g7inG^gVme{wN4?hXPR( zS1YQFKUy@Fl<_Ufk+!db7Zml!h$ZUCT(_v_!?H?IpIyA>Sm=$4`s2hDU(_FuK7Pgp zSGRVWjGbGxCvsFJhdGHOEb7IdY*BwQMp_s3GR1y1pCVnRPIqE!P6a!1>@+mioQ`XD z)r&`A)weD2&!B`ea}r8Q{IkfQ!lGBaIa@yMlplsK|3B6)V+NV<#dyQO*<1&!B`NaH z!9e55q=tJhTjZZhD}0fE9&YecD;(l_6a8)eYdE7gsqrrWyIVC9n0VEw8vjD-X%PUu z<@JhezDVS9;=5zt#o)%gUxLP(OKF4n+Dz@1FktG_68|#N{wL5TC4TB)VTpe^8PsBJ zTjF0q>S40YmHg#EHteCo??$pn`FkbwCdtvNz`qJK)?7^s^-(DeK>Aov1^zW;s2YH4 zNzDMP;fp;U-%G z*7rA4kFW1)acy1R-{mz8mz1A0KjY?Z5R{kq_kb#t_xIw)n)^7!;H1^I+mj@EaU@iE ze?K`Z>`Bov>;VzWEh$xK9>gGG@emqo9;RfSTw<%+W_)@72ninzgqT&O_p~8OI+N) z%TG!|5Zm`2n4Eo~xPKo*uw|9eQ27;nNp1fdRsSATkECzO6OY{EFg?Jjy8aL9t6+It*Z)aIPKU1R z|H3e4<8L(9{6iX9ocX$5+)eBHe@Q)mmh<9Hww#{;BdyDMnOVPpCj_Bez;(lFCITzcYGO3jOoD56k&8EBk+&`7C#8hR zauP~P`N_$kLZTPAnLc zIU|H18D>Ib&CE1KJa4AvOHhyxX?;HnX=e?zNqwLCSy-!l>YO91h0C~nlfiq=|4XidRY1|03ojQmtJA%zaaJa z(tjb`ShFyPxSD5e6}cDy5HI7hR{;QvP^1F@7Dc~tl?DJ7slR8K#UKT%aB(!&EP-ol z9AHU&Dhh|o(wMrHM`kIIm7@VmgDRi_%izYEWjVxnrNz11$Rwa~SQHwt962j&WYNKG zc@fKfELCV$z#t;BA{uK}qGX+KVyoMfJQ}bv30Db(t-h(J5Qp*0z=HxsZYoe$d#n7TI! zy0Zwurd3oh+~R{jwQVL{rn*N6Hpc+su>~4yw!}4i784T?k0OL%E3ya@=ui1cP2Y3} z&#n1MNeE*5wgHo~FOg=p#Skpq4vjV2Q>dOXF(a~2Ap|>+t51$AOkW-$*indkh7k0H zhy)?ni5BdvEpYMaM?Iq+A&}EcZG^yYNC{9NOVcN_UDEx>t&?5Qw`NydLjpNB z8yr$;VEPMNd!Rsq=9M(1%Z$wc1-oGwSup^OHM`>))H0>SoRAfzK*2yt8I+S!^cYq^ z!5(B#uIV~LADpA-&7R;(fC59+gM;dk1Qduz?n#-R{S;6zg!(F29s>nK$;j!@K*3%Z z#%%13#+rRdBWpAd6o|ViP_QrQ_e<%!4;1VVA?}bMD&lHK0R;z$wowlhSg}GKuImB? zd{`1FSfm@rxdWj+!V3-(gFIevF#7mO5?tM?X)=0ly&lR@l^W(Sju0;pud;Z-;TUO+ z7sv$rb$o<$nK-raf+N9->^cgKHAmx`UF+gaSnF-^f@3J**qnqCyx=%8sF3J&ZjP5v z`I>iCyg7#|loy4Sq?4LtJcSZ<_P}T2tK# zPH-wDxRoQ}iC2!o2~MM`7GcoaU9ZUO(?u?)zMCeV0Rc#WGtpRc7R?Zko2ls%4CFwH z5u8ohVSzTm2vQ#lF@kf*pw?|$jNn{S50jm4$ttT<1wY^e5|a9fBh~VG(4HhpD{SC= z&{%T;?bN5HGz{tUL165SU{ zF%teaM_6ROs{J1)Lw)m~AfK=OpQP@mg6?eX|8x}<47K>+PhihTm+9?m|7S6Pcsz&3 zn&)xNo~y(J#G|P8e}OD72A25kfS345NeE*5UIvr1FVz08Ui#dtpj^}SfIbLE&zCR3m(=}VQT5kB^+{Lk?+x1^8;yQjpl2AaXGF1eJVKQ1Kdj40sOrGvU*Niq9vut!U){KE` zcHN6dVcoaI0LG+*v2qehFo3bipu(cpyctJ6?OX)AZFwoTOF#Vw{^NqPxjNQM0sxGM zfyRSLUH4lS02rTEcmQAm+~9{sIK&kv`rEuLkWrje{}X}Tts4nUylzzWKQZ;R2!P)7 zdPO!*B62zL-LY>{aAS9w42?CD(+2Uinc6L3z|^Ou{}iO1GSDWaf9hai=|2@2)N*ZG z`cF;jVY1Pcy#AjJd#L-nkt|XUPXoP4a(7OLV>Mmtm%LS$iMW{?>{wg#ps{9N zTw53V^Lb6fCE@WBn1DQLzD)-{FR$|F2UV!@7r>1*3v!5|NsDf`AxZ4wK&UEzA#zsO zkfKxA!XlRYQL4}^fP)c34_XY2*hI-0$<-RN5bU;VUsz)Q+SbQs=i-=JoP;tKxojGSs(y4f6Toeog9L zE9lM^_iI;C!8nT#{&=;HbeYw@xL+3oh{t+ptXUt|?14#4Ks<_y`(9+(Ah5*6eQ$nJ z5`x&i4Z-B>3&s6L7=ncxqp@Za3e__vW<(aM;(k+dZIO6gT6J};uN*-#Wkp9E{QoI9ZDfS!8B?&zM1;+cCYriVCH z-8ZPWf(LPR-=B<}7G2#pF^pN+4UIJeNF$3hU)_t_X?4Fl=?A9tDbcY?ae6o6aPKM8g*)}TjleyS>;axGV9nFsEtbe!D5Lo z@rR&~Uns%VEu$vG=N9l@9921D_T~snd~qjR;_riz)+N5ov|rf!N|zbb-SC?IAOh*O zKN@Qez%{!Gh*x0~Xj|r6N;ohlp`^?|hzu$;dIK;A%cm9pG+>wh`*ii|V+IfIGhh%d zzy-Pnm_s0-IS1BHQtcm#fySY};ORYDwxTnK(HdXwAC4RR#0ZDD1WR7JFESvh`j3PZ zx0WPM@mf+<|4~%eA|84}%-Mdl2xc<$z|LbJ1nF=r8f%WDE#i7JwO^uwj7Y2h<4Jo$ zpiQd()X~D~|3osVW!$#O;44jJ_YtG{kSMw|_0vE#r;$&PED|q01 zN_6nR1?V^WYIvXwfh*dxE`$`U!HdvXb1|;1QG!dn!r`(orfT7kxfE38SixnW3RuB^ zaAVEo9AdQ6(%o%i63#d(3M;sRoE5gQ=v;TDh~*}hDl}JN5CORwjWyR$vd%WK)$K?g zE4Y?~*9F4PMG={HIBmf!c*vm0O$8ZTPaXB$ya9a9&F+|HZUj35auXW7wt;K*p)LNq zfOzEK782eX2%F3Zp7M(vRLH??>qKmsT3M1ya_pdLM|VzYB%1d<#0 z!CfT0J4aaLfx-{&Awzu+?j@hc5ALJx`-AQ*e(*pQ6^yp{;LmOkN|%}L@q>pjfOtHN z#+pZP%}%PAfOr()2al5FvA`1J2mj?KB_W9IdmK#8zJMP*fgxDm_xOo?R35@U_RlgrpcW#NNMkN?w z5B$b)-(C9-=|5 ze%b?SsB2gO`0%Azs*dS(!3REhtNfWk(I#NNg7yf5_*x9|7{oW|eAEnD=8+mazKS3yR^=CBJ{DNzCPZ2-Ep3)YT z_>~fV%Sk9fC4MJ^3YOka%pdY;=gLU43NIg+{{08{QHiI~i9aEz@pl4E{3Um*CeXxq z5j62PP4dvhKe)lKrf`UhSd3|R!fj(k0#S^HcR1Y|l%U0HP(c)84HayW78%HMKkq7qJ%U_p^9-xJ8qy&po-MtLa1Uq zGN?tLah?uuF>cquA*O%V;O))$q#g!S_=;I~XC*)uJK{GR`%OQ?gKoua4S#e{{Y#d?~ zQ^dh-gA(RAN($nbot!P65pB+#bBI`Of~i6?Ck7FixzJcMHzn&V6kFX+<{^%GNH}jG zEJa1zED{fO6uGOQj`^sozPlaZbMBS_x9v6-kk!3i4QlJoO!26nxIn(rjG}q;O_&H2Crl>eJ4M?arAINPa*cOOkM@9AS|s z3i?=@4D~%(hI}6SSeCk%3%aw=$MRKFFzVuiKQgW$U9JEReXNK9#A78i)~t+c_P8e| zARa}~$0}r5HL%3c$7=kfBm}X2tAoke7od+dFa!(NL}Sfb6sl)T%!n*h(8t>3S|`U9 zrY{eDtSiJlgFe=Shy?mrpBD7e7PzWl1L_&|(8sFSz^nXS#4c?%fdm4PmFyu9iL6hm z-qQ6D$cE@!vk|T#k(|35b4aCw*+kgdLm(17uVho{GIKK!$YvNuc5IHunk{e*YMEMM zPRNc@2xLo2*(xWc=%KA35czAsN~iJ&0@)gT2?VkYRc{+qk8%h^e07i5^kk_ZknL!R znl4?2=|^k~foxAkPLzT-%nlgFJoQ0i&5opzRh)mfLIROOAbm-{Q%XN7AdsCQ-km!{ zd0c)e2&A9b@qY<{bcucHxL+3n;ggsUNKcNEyTFPF3fWZ*^H4|wef)S0u5K+h8DF;x zG&!o$%IwAwLLuT^777`Fk=9U%B!}M}c9$-bZX`k>10fVSI|z+6d*GVgTg1<>x3q;q z_M`-plTZSM3?_pLmR^Hqhho_fbF93X<3DLpsWLKYI_Ks44IM3W>C&D0Hv5ppEOK@KMEA%Ql*K~jGUagamF zpjLic9ON)k50m|MmF~|;fI)hkV*&&m4x7qQkRw22&5^WTpYhV*q|Yjaf*eJLs=+y$ z)C|t{2o6w?b!2t)=Hlq>*G7%^INGFjN8<@`{TOI0!9b1$3EujlX=R=(4CHt+^bi9% z0YV%GBE3Qkl74Q-4^Bnkc&uoaUkq0IZL#e z6OVrsd8_b`OQ@>8x0iy?dD{aE&1H~+@cai2Udy2=Iy@2$7ak9PTtUJs17VZ-!D^() zPX&KmMV|V8UJX9yXIZLV14{UEEgF2?3Ds#|#B}G&2qZqxkLyWzLyoY>5rux-NQU~3 z+(bT)e%wsmw*=i;^yAhlDj0O}!JiUulP=TWqaU|p0P(m3jWu`Tnmyr(35Z7#`Z1g= zcLkOh{kWT-l!PF*?;bEY`vUrLFNR>@eQ2z?pF;JFi5ZcF3jKJ1To2~B!t~|QkB5Y~ zXXwYn5RsrCkI;fgwFRyac#L{RJ^CT%pDO4_n@uVKKV%(y@IwOYbLzj+_29?j=v(sy zt|5<{w@-3NWrKN2*xG|15<9QtY3VX?GvLQF7)EkDi^iJga1CmiSz=B|j#BXBc}jU9 zC#C3dt-y~L$)H@*MT$O&M~|YHz?Xm@FH`j^L3QW4n6*mpeaO5L40pUnMox`}J6^{yW@ZE$Yu+G@EZaQXA+D!z$D5>oE2UozfoT86 zM}-KOw;|AlLDa=%l>#{45zQq4M~nYUz&jr0rWCx@@vc~;&hB*~4L)57Y4qS|_#TXi z5RLc6E{|w@fIfb)2UoYinhdC0+8=RLWsdonBSbXBxh$gb2}W8Y8Z!TW$$u(c=2cGu zZa#w;B;x02toZ`h>=q%Og)O2jhVdmOe3g?>f?<431{EH?J(zFg(~1~Iqkos_Yj$q* z-?{IA7{mA$a+*tEfh91;cNl0~l)xC%MKH$qG|IymKi~$xzr!J}(GpysjU5S$@e_o( z^(Ik^*PDVdex}wI(b1b{@7RT3L@?8%=jQ$jS;&#!&{*?3O_D$~Q#T|=NRt%C_=B{6 z2HFJ1Nc}B@G5#WhTJ3FNjK4`eO!mzZ7^B^s)PynGh>}|VAJ|j|WBdymYet(QUTkS_ z(r1u@F-9jt)!>XlY6fQqSAVao7D(n1SnXwwHjZ~R))(K$gvt^eV=R#1l_1)tVO zD;#4SGV~C~7#Bhujv>859AiA{@i@l#xUpse4sqenQxeA*$Pj1aB3%I)6H>ARGA2U5 zv3?C8qs?rXi6IQ@brLkzOp0r3AY(GGcepGf|DWS6^TbRJ>T)Dw3Qz?kV@ljuGZlvz z#1vR?JD@~44w6DLrY2{F9WXjRP9tKu|D_7ev=~HSrbA=R^pvcVP;7O(m`5^ZAmNOG zunfs)GbtX)DDqYz88cB;eQ#$5pYyf^$!KSxnFUf1o>|f0?Hih+!z0mf;qgeu>?E8c z5H^_~EG>%sR7l30}O z6qGSP8R~no0Qo$Wu^@FX6m(~yjD@SHVARD2e>_}7y3BtMWh{yT#A7iu)+~-|_Mj&w zARa|f#u8*%GO)x@#!~#GBm}X2OM}VT7odz~Fa!&iMPto!6sl)T%!n*hP{#7)S|P_3 zrY{d=tSH1igECfvhy==5nHH>~EpQdUs?_uU2g+!(2P9C2EMyO5NML=7i)Zg)-Ks zlwLV0MGtHRWo$qO<(jTl^l3bL7WD>S0%dGS)f)xXqX5bf@7xnLJw_@hV`J*B;6)5& zY(hp(jfOHd#V}@OGc?w0P8wOZc_>3%Poa!0NWW!DzuHKFGPZ(1cd!t3acQNXj84(~ zzYAq-Ef%TsdtE4lkJlcA@lE-d|&A@uX+S!>;y4L#GTPt(+}6|79pO6Eut-y(M1WnrXinpu7@Nqe;uQ-?@p$Fzdkz+?LVMj|AD)<{3DhAklCCKi!FgQniyyt zoWL5hMX<(hG|6SS8Ptx@7Vg-a z)Wc+N?KN`dDnK72H7x}S*axJ{GMU-54ejw_^lA!6Zjehl5FuM8DBr!z8PZl$BtPf?%xqqtRG% z46dyqlViON!(|~RkWhI}nd87$4xStjssNsxfE#O0*=Tiu@M!IRTTct#-XTw|n6l?PIaJXb)V)(i~xtPYPbSj12XC`VaX$ymC2pUlDX? z;gu_^s9^lX2Y+O}O1fMj9$vW`1Bk~pXso#w*X-d_Oh7z};Fasha(!Tl;guWsNl6G| z`)&l2voF9aH(>}C-i*eYTPRe|n3xe+sNj`b$#q+fD@fseRb5(g$q~ft4fm&pFd#FW%?DOkx>3XQ;9`vob7uS$e&hz^?q%yYm2w!Bqh-PtuYKKE=SxQ)J{sY2f8)3}c?2 zL1WFcq>%-k2VNu)De&?f>7P&ON5!Aaya4g;h$714@=w7qFNz%{FwEM;2ZxdKtsyUo zeX5$M3(D~EOi*Sd9YtS;K@mXnirDA@npe@s??2({mSvNnb{oR$990=+MsS1xjX0VG zXx_j`Yk)@b#BUUDN|*UJ@}|PP1))gax6xSh4zAg4M*IxhOk23-T}pT_C!qwcd7lg_ zSbB>wAIPVjizD;O;hO$C@4m-gOAc5PUnMeR(9VMfm=D3+_&fn+K9akM5>RHo2$cC) z6g534^9gS7Q%)S>T3)<3^^;$wi!~?c%V&__mY)PCUVaLF`JAd+1VQh!y<@w-5W&oe z#k*(Ymk@yY{|b#YU*qcYIkjD)ffPt#mTyS=ZJcAU z)Z^ihzj0&DKOEx1ow+z>G4>%o#s$2>KK`XZhkcATCAN_bHTF^ROIUH_&FGMT6*mSN zYsSR2HOMiRS2kRh0s2MrZ^p(4<%q^OpbCh_xVW)qJPt8VDZt?ND+y#A5QS)rPtFSa zRdg<#0DNw@N)?(3F^G6fgvOeQDOu;4*y^?)k7!In!bt;R+0U8A6X2nXA{P~OF&X98 zcX4v?ITuTQWi@A(nF6c`#FS|8t`7CpejpWYK!$L89psX({P?Lsr)7HLQ;5Tw zw4j17G2*Zm896~3aabF}n4fjfShFr^_z+h#&MpZ+ia4xC`t?)#br6pBf3;FM4yG5x zrb^>dM-Fx$zebs&VL6@;)om>WMO5W)^}H*W$V zEE+)weQ1V<5O%~3elvgrNAPv>pKMWe~#dps{8k?bL^^Gz{qjML`II$WS#5dytx8&=A7X-GUI5 zlO2t-#m_whv3GVLpj7ar4_x~uOyIhKoo><7&$BKSJ46Qa1qPhDphEXz#!srBpPdu zqGX+CVyoMJJcMvG36BYcl^_H)0Ukmqa#2AD$5MWM7mov<)WG3*KU*w#E5KbXaedkUEpK}hK03qmPJPjYfhttvE3t(`~ z9w)?P=femGA)HCVvvPz*4k!rWY%Ny4gm4aZpBr>%A%yd)s9>U%E_i z4dk8@S=9SzkU1n3UYy)jI1KN&d*3IZ?>U>I}oAR22PA`KtZipD*u z#mN*Vc$oB$r1VnmwucEazM4nDnhK6f76k=7COS%>fH{iGCO`pNX+gRFU$H_Rk?WTG zd=OSH_tl~_k3(}*?mr>M_;UYA^zq|RxVkmbWW3yJe43*w10~+2=Ae> z=6zZsZZ}iwB_ha$w6_0%v>yiAq_$7pEUfK6B7<77ZEO3FNj*%8nvyS+>7Sp0P~A&d zx|2du_kIEk%If=1L1WElv{j#o(om#N0#)CCPKK(X_=407#RmRJEiP|`l<(~_zTzta zxj=O^ZWm9#go2U^|0|H-^$}W9=BTRhzac{pEBtRE#8vpxE3ELpqaI)3e~%k$e&7(7 za8lt%QHv{l@i8uFRfYc}1-c6VC-fV)>k5CN;^$a+hb0$#^D|^%<^6)jnqP5kUE}}e z)eV>BfIiEr$Q$!JJ}9s8{{U5}@&Ck)HGgr4kxEN$w{uA-Vr0%?uEU6_o7ljjJF98h)s6lAFHz?9_kb^cV;J$2BXt@Ed; zqJqH|AN-kYTIn*$eVsoY1`vg#+tsZ@GZAony#Dt%eDzS5U?`c&$WuCMgxN8g$S#G|I49OvYM98yVO7817h zmA-_`D_K~&%-2k%zX*nr6N{p;W-(lYS|*g36LO-o(qEiXmdHsddi1JFe@QYZ*L1a@ zPsq`8W-0I`mHyIHy-ZNuDPPxBsnVC)!gTFEXh_%KA^eF`UuPuMzZ}Fi<>#BZ&;6;) zqXOcydxoZGL4^t|ON%P_7NY{ok&zRoDt@y(hB03&ps{8}(ny-*|6D-=lA;1Dk$&Zr zek+8hJu1-cxR_O-#vL%kh`2OT2*RpjPYHq`FMSmJ$14zo?iyHtHmoLgssnpnw1JOf zq7C&AimO9+gg2}q=6JkeP4w}LOt`w0*<^Ixp0GAYRdShiI6}NZe9Gbt>tdue-XJOB z_lotT%hVhB(KqWuI5M~w8f!MdHM`@8zhTE|i%s;Vgbi~NO0bEI$e@CzcN?>@eA+30 zhFzhsl)qPy-`sV7udoSNoAY5YCb-0=7-$@y;1a7wxWs0(!{ZX0;|9O1#38O{v7jLB zL&1?zonR7Mg5NDXiA}ul6eh716}5U>9NF2f=E zg2tMiXrn(A@add}Abs{I9AalOR1HBtQZoc=Bl+Y{72xUyOVs>Bg-m!l8kdNVT@YP@ zK!1JQ3>qVb20I@^I61b(ctJ`tgt^tC&GP1EO)0=q1hLMh{k?stl6KEb%u$p zZo~1&!vQ3;fv|J_I>Gm-Ly?0DbvTgH>pOT5_?(0Fj4}s<5kWWv4PN`8b{z!q*#*HP z4u_HO@IcsP7I4=oa!nx)N06t!Ye$05xmKKpN8xjLa5Nfxxd@eL55!>S!3d->@P=ba zcwCOK$b5x298ZS&=AS@5k2jo1-6sXzS-j!oDk>Oi@xhHxWe@1@rDb8xMz67g%FY84HwaZi?s#r*nJ80jC#C5P9l}?hRicJ!5U=2daOZW z>C@;^>3Xc;GW4za53V6~oP(EhNF{)|LfG144H7P|S2I|{RTxG-T#d$>Yj6!} znM`6%$cIv_;aW<$E+?hvF{`kK>&c*8)2DxZ@{OJ>H-Im}8g8WOn}X_2c`vgP*3dsQ zQwhS5JvVqP>b318dt>$qBaX!Tr z?jZf0DZPB*PkUUUQVh&+h;&BrrgfS0tgjj+2lf?=i!boeZ zK&IWV^@pX)bn01@%_9(m415%gHILz%-5tcYusgKH1^!D3kLM(m-~vyOK?O+f4CYDs zv~w*aQUzRK$k0A!u_YH~n<7g3)59gQ6%67Rx*5}4vWkl;lcT3Qwe1yg)Lh91HcA3}(ODWq2j zQ+z}{9;WyhH`aW@A#M}$I(m6jW86Yqj!SigTYO6S4!8IW{l*R&w`lR_X#vJ8pBwWz zgko)ffySCIacvD|eC72Imjx%U%9VR-z6MV@y73LD0=n@nZmju^Lkw&RHn_c0A|HoL zp&Q?mv%=mPok4#PvD`URh2}>LB0N8#vF2w=)`=;$x_!^18^4h7*FaeIqd)!2r^rJd zMP4h&<2S0T@AdECb6%JHJW&-(%^#44aQ%q}ug1_M9WIHE3zx@1{wCo+fw0MZVZBo1 zufjq8B~N{SN1HnFw_*m54hFb11{!=J39i|LlX&1<8i8d2U}P*3j-4Yc@<#z9$S|ZEZqa_kxpIb9a*P|t~pl{8r z;$rsAjM+G(vck+RZ0*q!iJ@0Ahjf|18MI_h3?oVALSxO`xCXV%Ffk`2Nhw+~52ehT zlT!3>S7^z6WKgc@nn<7WqbF4d_!6{aeyUy|s2=5CASu4Or*C>FRmjPLw4{PhF>D(0SUNObZ{>~RF)D;Ri#iDQQ>2mh{{MfaxM*HBA8_v zvCqRS%c76pR>IXS$tJ_>w!q~%sFvd=DW7(3hODarxeOG{Wzb$- zrjHpkXqO>__UNOMvyWt_JUF@rn6)6iIUY_#2>`P;1{#|t0L;b_0J9EF^#IJexWVry zafoYOj4W6hxiY7!bqO4^K2*5%D-n*@uYzNG(UumG)Ejm0*s%>nFcWK3Inf&$kYyX9 zv1TJ0DnVAHKQnf z1+Lf}_Ll)STY$!zE$OK~Vy1yipOFf<*@_HR1KCMx2J%P*QWf1BV!>^M#ki?ki$%|Z znjlWq71Yt_kQi+Z(@G$nZ9sx|k?2ENh!mu=9T|EE>1+=n4$_fcA*8bd^>|394{og4 zkwe^gT>YTPUtr}G`u5!urxCFJ+m`ZV6W(h#+oi%TZ28j zcx#5s0+zqQs22ybEBMQSp9ZJ`@Y5eR)-*Z9@TWM8+offG;$SM^XE$H4u$8gD6?2uh{DLR1f^@LBc%)VQ24=Jb4}lDvE)Efea0(AA`Z*b1@j{ zcAFuPjZh9ngSVDwpbn)(&V|y0LVJ^NpFr4TF0m{t@?L>L`;w==_xpj*dEbpp-yh6y z?*KITx*1xa-4kz|dn2%v01zEW!h>>zMZPJ3=wLF`_w5k!d4T9p>OL&!&H_Y-S5d)v z5Fh-}`3UK9^>~2jNDLqzN1?IiXk4?$UNHgjC<2I%A2DYfhq2J!4`31FZGo+=7C=<>SdqX*vfw>jB;od%c9wKKTy!@2)(pcnWS5Jl_Y z`F1Jz61eCxs{T(oFdb2VvX zY3E?_~0v_E<1{Ey5*_iv}(@wzx%fX{& z-`%=ezNm9Q1U1*g3QcgL2QbihCc%k1Bb?|#TIF$~hj4=*f8r1qc?mYz&X5EWdIZwk z8kM-kYg9o(k5X-m_~^~JckIJsBADqi672migdt5HM`O(sv`IqIO#P53AyZQH=Sk8& z6=)OmCv~_G{dt-UYEx*7{yanKVY2nE+P)BKJ1YU`>3OONUhyofD#LW11C2G$(|&y_ zOv95t$P}jY0vW1?=S5O8Jbe%z)Yj|ED(OCg(=Lh~jn&2Zm!Pu*ta%wEc*BdvmHDo~ znpertL$KyG2ytMI^a{b6*Qv*YH6w6i%^Muz>Yt}1kTEnP&cNWCzW>g??jo z4b3dm{iHT;LmJlXJ7}zV7uVJ(%zIw(a9Kz*l{jeL2X#5-@&Tv<=JFwKtoevTjA9Cb zxNT6v97joEE+3P#!ZsM4Nk0*>+yqmF=2HwJFrT5Z=5tEcStz!;oy=n{Uy$(2K-k&h zr`ePLC}_7xJiJomu7X#-qOSVxehoh7Zcj`!-#`ok^eq~^Aw^qsfFvF+Kpsi?o`gRH z!X`6>6-$w$3Q75qJoO#@34G4c(ro=1q;TdJH24Z1>eJ4M?arAINPgfZzmf3w9AS|s z3OD(K4D~(vlYAaG`HQ;$4!X0r$v;(8FzVuiKQ;a` zu7^mbK;N1v#kcGmHB)g&rGuGT*xExR5))Rf|5AM~|bK!IwZJvrzS{LG>tyNW@q7h)qwH3L=?} zmQ?U5hDc^7BPU8jBy(UG^E4+KYvv-2tl~UGB7sODlDSDgPf9;3Ad-0@-km!{d0c)e zh-5yoG=FyM^(Z|nL;p*06lks(%-ohMJ zX=N7S2+cUO5`F+t7iFFTLoZyEpc0_3F%Wkk*_ZD>8vZmd8Nj zp?(NUMB)0zxv9(oc|rbzxr_OtKzmtXZF)=tE!{sPti`V3J;Bs2ZpZNXE)JB@5X-J$4W|r+R->t!q6MqO8}D%L4vogXl7Xy6kxJ38F~nqYyu$;Fp*v% zV6rLoc)(;c+*q?YhqyP$SC^NDG)7It;}{Q6sL2)-?@*I1(Qh27QIi#WxEqy9Fpn`Nrd^u-{evlAL?cBW*Vlwzyf>^y$bkAz);uydsz&W{ICihNce$}Ut` z-{)Py=X~z5ou&a<2vvVHc;$!&=}<{zT&O&fvKt8p1i~hBWovnw6nU$Vl-Wj+);4K5Hi$vXDInRoU#{n?;Uh! z;go%9`SGrsf9!}X01Bl1|XskH^*X)r|Oh7z};1o-i0|QG8ryRsjNVfylL%8^3cGdSfah)Cd+qiMl0 z+5%Tu97{c;9!`<7Qx!O+^m(6PDzc_MrXu0>nRT3WJ*ILz`qrF)Yse<&^NAc%Iblu` zw)U8cM9?caS-MQ$45o4lhLIwtqOs;QT!UKXmzWb$q!d#*ol?%oNhx}yD@^4~GAP${ z?W0fh(Ie_C@Fkea*;G9&sP5bnb64p*UDV$fRQltW9o=JBe07iA^cbozm2+rG1)pL} zYb=cBRa0@BD*&SNSPh!j(~kn|U&^rHe(xftSIP(*oLx+zTM60zg| z5>vTU>{GQtT}*|~WMV2kK4@MBQzBsHKVqE+RxU>$Kjww2TaZl#*=+?^a#ZD(xr!qM zR>Z|DuyQp(E$pJ+9deM*IvLOj}^(21>XwC!qvb zxrq!aSbB3YH_N9Lf1P$f|G`80;P-0=8UH6pw}83va{{8=DtGfIAW9I{Gbg%f*k8eDK8*85B z5SOk0-q>u!Vmw1UjO%lSXFNx74$pWV{l*j;&nWq=^EmG21xUbZdl8K_FX7r6zIfRy z8!k)0e`ROZ6Y~m4%HfJvK^5SN*KlLa>l|W?QuM&>R1(BE915-&LCy+0Rdg17L&S2Q zN)?(nF^Fiqg~pnN~ z@pF6*557QyZxNyr?SUBVJQ#s=2Kew53BS$}7MZWWhi}MG-~4aM=fQ{XsQde%I}1Mi zP(=kpEk5|8*^km?dVBEUCk!ASKclhc7hJQ)Dlq}^C;}gTCChJtB?cdU=O-m0i0%6W zOwPUlKKzLxSojwjYyPHCJ!4`K9R;27d_T64qY5K@8WnIQYm1@7q<3T zg9OYgnLxVC)(qA#A%>9=6QQwYVq8OHnNDI($cR#`VG>H2G$*C#ajUR~$;hBw)8&9Z z2}jSD$-$Rk4O39{ltFdp>X@oZSOcpEoEX!u*GNxV9#;^*-19L#-6>pQDr&7@e~c?k zO-4?N#ucW)Fy>@hG}cT<8d;@zTtS>pafRtgKSN5t0z%OKdt=-BZf1licR&zDaVeuP zgqcKV35L+3RKYi$v@@dMTTNybThvjyE?&ULCh>y02f10GIf4gf6=OU+FdO>#4KQ5Y z8fr3r4j!0;qbfzroE#xMARcAmfw?f!8Xk~|_N#hs=`w-37hf|E1R&SuMPto;xMtVC z_!QQETPUD|66ViID1ibNAcG2wUi)T2`LyCU#10s=YoC6olll(axvSM%77IaMJq_x5^}h@hVe*!4lNoB2;>t z>>azZqzGn~j6AcKf=ndN(rBz%hNekinyEVyGvrQ+AuLPUPmOUnYG(1-i#+r3G#BD;V!t$ub@PxP=*W(JFSda1@Jh49djR6{-DEa%c z3Ugz6K`7St257A5jcaSfVneTgxGcCiDtT)*0#7-Fu`#Fugs};3tl5-93~Y)hxV=*% zABRjq7@Lu^!rmDjF*g^n+&NQ)W(y1=JX@l%W-Ch8i7B?aea}M}og~~k5SD#CY=tTE zs78_33f0(#D(ic_E%=<*C0`F)#Zt2!q#<0}qrpovG)ad`qT|BlfsQ^T+%XU~nJ+9y ziu_eTM_=;P_jf1oIe#l=@Xla>Oa0K`D|M(+=cOyCR{as-BvBuApL<|tf)T4tD-6OyD93^|%o zj>$NxNvV94=QeL_&(xg}<=5*X6W7cazD_w-E%_eS0{n2R73se3URYc9bx zyTyo~VT);tw_HjIm*pgs;4S|lg9?`3Ud-k4Y3EYNx+=Bqpgnf#yYp^+26heU)30l< z{yTS>E5P5J9ZNBRSgyoCV!0YO_z5!(aW#t>1<9ZMUH5=NIsFNw zaxH|oH7HSv*Pwz_uA{aV(a@W1@7VO~MKF`2`)1w%8OVhj(O7d6O%cbNsreEUq(cg! z+)UbA0&N1Jq<$7cD7TV9t@XAL%59_`COhgf_2(c!Cf!aW0S0b|4P_9?9iXx1PFkxE zb7?Trr;&n4hLfRcFzzBXgCRfM&0^jq-iBR6)@0gO`?}SFeC=pFAimxW6(u0ZJs`oW zI<%$CRRx0FM}{7PAooLv13{!$2!cF7Jst#k5I5F5#33%^Sz5#`hCRf|xQ17-$HSE9 zV2?-8Z#r6hg569z$cze{pRMb3E?#4VOiMpEW4V1M>u^%7Kk1K^1_F zr*LD<(;Q;3Qk=otcd0Ql`1sPVGsd%9*s3GP_j-ovDNKH z9@u!1gf9ic&P8fZf(J5+yi`EO%T!U{%U8hXyzGW$=2dVb9Iv6l>oYV#heNz~;qbu4 z2ok;#2%F3YmJUV!Dd6Hw^3?b5E$})2TIS^2Ab}I_puzXfP>*&(Y<5nJKxzZ3c#nkd z=Lm~DP*BAOWT@}Khvf56#YfcranPNGDn6;Ag3%Tq{2}gB=`znfRPh-G5RcE%Sn~z0 z*#nrEfOr%^6dOXF(a~2K@~rc z>&F~dn7%wz@skku4667UA`+_Li9>5Bk7>f+bHC;RC({l8z85?{FG%*fUj~i6;i{dIl6DTuW zm67}kN;rS*=$@3~m3vaA$36u@j7OantdBv6@yW<3(ICVG7{-iDh{l?UNF&QM4?>8` zDF`t!=_g6)mqWU?e@ml{=Vnp}a_)zXD`n`s}?&-+>x2m>ulRMX+uX#9$5#G|os6gM%Z)U{2cN5resKgP-x@5SL!r z9}VQxCxF2`kl|L5#3)`x3NV zVL=&Muo!5pS)8`&^Hds&^s%APf+fgMH55ydnxW_ge*`TsTOsAcv#KIikc(4CV=HlV zDabE@3YG>5-pHXLWqvBCU|BNs5Gq&>LL5{ey+Wv9dFt^{!3wysW#~{6Dy!#CCYO^!OG}2w$ebsLUmKrtO6NWcdMeYW;I+};{>aFb;D&bOi`EtW)0Ak zqXcV$Dxd^w;l`S^Im9@nMZ4R!B#?1L6iToTIV)^i(aCLH5z9?0RcO}3Ai}Xe8f$t{ zvd%NH)$KtZCD?$3y#pbCSf(9RlS_UN5)?V9K!Odap}vzFfzLTvcHGDtW;O;hg0Tr2 zyq`h~bTGts7YvUPY(~P(17VZdz%zW2dkQ1if;{!z+Y)@vy%zbn6$s!$CmMXc3bkk# z#A4^d2qZNSf^A5+ZH}RLa<{M6^ym`;7@0LrOO=m z2*FMmKs7kw$SI`~LXcbV z2|ysL)&m3*PoGMIrRxELA?RB(6xWbG&dI$vq>{kwEo|)p0tuN{vX69`uNi<~UkoEB z_CsUM{a1XW3=kYfMox(a2oA?EX5f!@A2~sv+4GYTffonix&9$^upQh4Kq)!cn4_rrvs-d`^)C@&}4-DyA zYv4|G@qwI|9gU^M(HkJY1RuB&BzWC~hLriK@PV7j&_jIS76@_pfbK5!@cjiu}01G&(f;gErKcNZFK?#8t>K5&m$ zH(VA&QjcYwG53O|93Qw3Q~@8jA2-%Kz#+ydE!W+)C4r11qVRzS$ys6BiVkiMiCAu0 zsY3HG1`&=&&{*>*CF?vBTiqVy@qx!k_}@TSiVx&wz~ci&PAYuhacZdVlXn_uf`0j$?@quSZ_-r6-G8=e=FLF=e1J9ACzI)Gu&$-tkA720g zTzC-;zQ2T8vHa-tL;_=Qq_%}FVG@G5-ZH!>*KbfutA$I)Zvckm_n zz#mloXHY#7@d5G5JtWhUp27$IqRtA|$N0eCWaN}+eBd7pV@Cc(W6fyOCo_`A2gKzR z9~d2!_^F_jzGwKrm=NU72%;t~Z4^E*mT3In!3V|`o79oIEi6e z}g!!^6|#iOwD+u{S0Q^FKE2_^Wzlw?q0(W~A}C7*UK14OpMfBs^+2KV26 zj{#j8BA6Nynp5HIkw65~V4%^JKm;d85W%!G$3q0u;Re53#36Y^(vWulH&tXof)dOC zF>WbIq~fKdP=Xn$uSG=kKG-`pekKvjRFH^u*U*_E1sO358f#{yG2(nPbwJ{Rq)35+ z*+@HkpiO{+)YC$sU=A{wFBz%^WIj?eAe$f{@;bqguFbdtx`7zvmQF`wA91$>T1r5J`9XqrPH0Y< zw+b{^kPJNp4HkkB2O3DP5HwhrdOT>b2yU!dltWz8v$hIdj2noTah0ragT*M);RcJN z-`Gdv1}*mH@ajv^&S92-7_7u4(O9z-uC1YirM<@CvOK14<&s$jWaa3=vY-m+!E(5< zW_b=VU}-V$wlj%n92bQitU%5R+gWt1TT#SvGfNekl`x2itc=E*RVY~}oY?9%CXXJh zO2X9wVdrAq*f~6aP~@iq5LTy>`hKnfKIdn*Y%^Pusw!g;SOl5=|iD<#>9-sLIor2NUpv) zt}uOh7-1(N?iq}*GejgXLO)v2r7dvh^j)ZD)WZnNVJE8ennBT{Awd#k?Rq3ZLh7?= zSLu2rp@F_N{c#N$_I7e=A;xoiWQPz$e>))HHAJwM~|Gr;7gE%Ayhpys2+((f_UW~nCT%`(dwQu^hPu-*St1Pej#ydY}g z@<$;F2a3l39VFo(u|%D=>mmt!auP}C*75FOsE@#eL&PEvCLD@Begp_tw}hGup`1j^&{%UUuGz&e9)-o< z7ECyf5{}PFC;<~rAcG2vUijuj`LuHhq;WMcVQ2v1S+z5vQA}@e&UtLJA<9L)vo#Z2};qUKRof=aE6J;I;t5`J^5udtcet zGT@n;jeh_Sx|u#wNnZf{Wx&COpt0s6TB?szX&};Ph5`;QCPURgTtaFFVm&0H0}i(6 z>IP_#2~tPnGI8@#NG|~lE&~Z(LZKODUMj%gax(M~Ft`Fj9AF^5Lcrik>hXZVRk*R{ zY7TMjCchyuq)UY?1`EW)xF}X&!8H`;z=CVhZ(OFqg0f!=h_lmN2N76t*Q2rK23%VM z1vh$a!(|yH-`t;Z#oPpva**I=Pz8|S7Tj2KD~A}Qv}SkPl|(U)hXM(1BWH!}Dmt;< zE@HV^r3%d*7(_JgL}SfxO4dmxwz|#7g9LYx@a{m^S@zyw9DffG6#1wCf_tc-zK{2U z&-qx}E^{Av5sLfK;0+KOphF>^yHI#=;6V~T6bPHl1)kiCyi?%7!{n*&-6P<0-W4a~ zqxc*iJcb5e!$Bq512NcnFaik;VBm2QK9M6VGG74$Pm-a&`A?D00|QS}_cK9v78rQ8 ziVB8WeDDXd=cLO7_rSpO7(hH;Kx55|xMq)7Vglk(1Pr`HmX`xd3=F)&Pf9`%+xIG% zoP7Zpcnw3a@O3oSjG$0GV`4^Rp#lcpAlI8Yt}uOhVBjqw?in!fHbf-Az&o_yU2TCo zbH7JDqaGNLvq@E8AoKi9Kml2^9u$yp`b>IXx*inx0DWsd#5H7(^YJ4NsT?pL3tM|o zKqBUqd?H<@YX%hf6vIe~&(K)&Ij%u1^GVDJDNzavd_gH+=A;xoauq1>6&aLkx;D@! z;^-0cHTV)x;2Wy`HmDwnpn!Pg9+2q)Pk{p8QD+6~V^H9GGIB~ZDDVS@F(W^svF0bz z$Rf>y0^)KC3j9p^UsC$zkgVMY1%8DfcRmm`aXF(vf!{>q{|+edyI7)5(se-rJ~0Uj z)IP@j0o4&8@TXYg0fE2J#}D)1>XuKF;d2Z3AC9X0F#mFdfPlD^1q4Q$p&cL~v+Ni2 z=pb|px?6z27+^=5jfuvZv2e{UeDNqO{I-C=*px6%PC^MFFfJKXSoESdr`ve@gC;|s2q*)#umdpg)v1}01o z8f#{t2l@z>1}J^jC@^70GE@!FOr&Oj`ocAU3B9>gy8iBN0}jjfAhXT95QmjJ9~x^qaBU4f%a zBng)agq_RvU|u{ZQRJ@zC6=bL`u;8hKIdqx!E)Xiz-iYzen-N$504r7};Tk!@ zB3Bexu_hVnyRsJfJXo_Tu-`O1Rktd9|MR-FErL{fNS>n zCng{sMPNm5vTPVwVz6Q(eo_*G*uIUybng`1+WW-|)aGbUz47Amk}b8>Bw z;|kN42P?J|;+}yOTR}tuR&>&Wt+fTN9@vI@Mm<;|XQC=#McZe30$j*i_P~XN)@RkW z()GZ_cIaEPJ+2{>oWDD8Nach1ALiaNK#Jr08V2I-Zp7KRyFehGjmt)10}I0h7E(aG zBvaQdvq({VlWw$Yr2NfC-mTvGz5Gx za8aS^pxTfz&;#Rd1dzH2w@O$FAan2hmqRvMM!qI?O}iE zGV3PX1egOL6iFMQiOhkxrZ*Sy({C zO8=1~hIabjdN>T+l^y^37lQc}H8yQ;DF$=K^aWSmP6?SnUnT~Mnb>Og9|uz0 zK*Ae6VbR+XnF(;fM4pcdn7D}w8u#&L@L3-V-j>MPWo`j4LUAh^yv#xabST7g8wv+T z+)lzfJYki&z{()cI|WAENuI{Ny9<2QyBgUz4g_%FZZ!C|5o*ych{e{0@knVP5ciVs zz6@cW{R)A&pA3!L{{Zzc2X{_;M7qpyhd?}v0mS1mG?956 z*Yp`nOh7#H5Qrzp@}y@85s0VwNkIrg`<@1qwa+6E&tM1^K8q$Y&rztJF)<^sP$3Y{ zlk0^Hm!G~Y0`Z~{H-|vH1Q9U;@iHxVMO$Ex;;&NA#77{?zAlkj?=k8ii`JnI5>A&% zuSwUT4zHshnKy9t*<*ctlS3*8%y?m|k2*-ioRYVs%XCel4sT-^De(@P$h?cISIc}7 zb9_n^q7Ls-%KI59c@JHMI($F|<(e)I^r<*_#(W6A7&HDP|vLAL!fSp5JJRfT zG?DoO*Yv^{kNm=~iwOKl34diI6d(eBlRnu#zvtD3zM_N_7n#x;Fl6B7`RJb0lGS=RF`A-vF+pA>{3w67nStbHC{ zSRX^Ma04`v*^ol@jENb6g$iESh+G?Ixcu~G;e}0vxH))XQ;3M+h0SO|tG2+N;5Vn9 zi4QNViOssy3l8}wxEN%R_3JCyH zoRV#&%cM<#4BKHCiLpJJ$n1ctSIevtb9`bHf(&hxvSUU{-eXyT3_FoQxu)w4eXRr9+wzV*0r9cMRs8N%|zZfYeG#tzZ*oUTgWFMNzkx&5)yHQ^W%R_*n zKN&e48ekZJVa!H5n#k-<8d;`UfI-|%0EU62AC%Aw8de`*sNuEgfDr4ts0hm;1uhI0 zZ3W;$jX%oZHHCcjIl#gYu|l1>8wD2l#3ZoL#p7KC1_bcJP_fCu3sv;-`#QMVg;Qk! z?UEhFQI#ELI7bLCh+}DZp%Wvu;RTsvx0FXnm$}nufXzs-BEj}V6B&bRdbx`?e!16$ z7DiFR=!}E{XkiQ)R7mtvH+#vaCBNr!_|VQ#qfN&!3oi_B?`$8^Va(o;Q0<2$69WtT zV4(6?3@qFg01Nxl90x4yha3DX4u`nv3cfxu*Mb;UH~?boI+93*>qx;05%txGh~E5K zL*ow=!Ayf@3_S=^kP!!?iOeB1Mx3uE4oF;(6bYzsC}|J#v@xiVc$y0;98Lzcmg|BF zN054~?0!Y4NnR!-kb(rK1f-BBM5^l}VMh_5a1>}Fb2Kg1$EqYC$||$3aa2ns7Ww@SY0oDRNh#2`7@FNi^Xk2(f5_ z^m5UJlc~p{38&yDGN*Egi@Imc*o9z%xEU7A3QRbSGA)>JI{K9vHJDHX_>I5mF?a7U zXFv?r;+be7a~7_(p@g%Y#&NPhX0Pd!84J2%B;g!Tc_iUn+(hO)4l!g&VQ+UdiD?)Z zg(RF$&JsIXaGbk9#Bx7N6q*Y$h>%=_CNdXOvQ9a%)$UCWNw|cBmwLjYuX@a#2!|u& z`KfS(%c!JrKQ9NL^|Ros9`kK8SAZWOxe^UtAE6OCBoYA|5{DvOO~PwDVU;<-<9(io z3Prekkc!fn)jyVsot5$-6Xg7Fp~+#&8x=`!0Lh;SDM5RY+aB6Byc>7$vLfOzDA2=|cX zUe6MO2>0=mf)IrE-47;fp9c{hzz{5a5KUwrqEJ0!Vn$%00udf2*CQD&KYdvc;ZY%O z4n%kiB4QBXaa!<%w!og#pQN6N4VMInUnGNrtd zk&^c?RuICgWKgc@xa==RY=M|8S! zL}LnD^Yd-&=dHF}aUg^EY@eseF;RgGZ_=U?zJ(yecrtRrG|2E4hB04nqlwHrq>*Ku z1sNnD3CQp+>EBD}cR+ZGL542H#k>zS_OKyFgyoZhAwCd$3SfxMVQ9`D6C4cD6$5jC ziVww3b(U`wsNh4HKt-31jvqmN08@M{7CD&W6ZG*jKe*b(S!ICjw(uE8ReqVzIYO91 z+)Bd~Utpv*Od(m~wu>*N%j}!*6JWlAa3t~9Xd?3suIWuj{PmkoT_EFIO871#p#aGE zo(w8zdc!e4$fs@VAn!_4o@0iM9x9IoU>T!Eb_^VC#tiR2u+rYy*)h!g2tn0ZusUNr z<0lMM2E};Bg8`oLGp%xX#xJGL#L^ zq@-qe`XfAobx3ly$|Bjut&zTViIhY<>g0Ayuxh9nw}7Y04<0Hufot49UzH^4Uj`d7AD~$p0LUc zVbzl7s6s{-B~RmyE(Sj9C_44Cb#YL@nOepTkF%q3&h9?leBKTp1ONy7=HukIPG!E5P9+D_{WeSP@NRR>CzM4>1Ap z$iqigCd(?GCB#Qo=iL6VizS4Ct zNk8->vp%jqk*vELa7d+t*-+T(!z2wBGuIZ{ppUQ*B(H7u~VUjJWdMmHG{F@f8sEJV#cYt#shL7`;hkGLu-BY zJSXJJ{bTN!)cfUDmrn4UkTz67hxYf2`BcvqNI1lj2lJ-Gc_iR$)g|-`7#9O8b^QXI|@y%2xHx?G_bM^U&%FOEjPa)3rJ z)@Uln%`p&&ReUU($Q*}jZ2;qVr+b_%tp$qRG$(+e7{fRbR35`P2{(~BnL`X`0x8(- zQQ{rON?{nMkh8@07#tc;6|vkL6NTn93?eqCqlwHJl&sTHY_;2)!!XVy;aQ%rZOx|U z#=#hQ9xE8*Y^rPA+p>G(T~gn zxcXeO9zVz-l@aD4VXKd4Nc^0Vho#HpP2m}jU>FJVD4NJThO1Z0>=JW)f)wHzk5kGM z87X;>afN3*Ne1Pbu5a|oJ$N)d1-=;1c$%u8@v0~Kmtu;q_HmmWIu+9KEG;SFQ;2jt zM@CMRLNUzq7{)xkfF?38l13JC_H_>lM1pj@MEaK#`ib$Sn6E&*J%fnyutZZB$g5&U z0S2-`{>fm%d@1H@VxOu68bwF=JSIBQ zH8lPk5zGW>#?Wse1sU-jn#g=lW5oGt;(){jNs)jfKaloEPaA_HiKn^X$WLTYtGzBb z@-wN&%AQ*ApDOwD;2{wSP6(w9qksCE}z^ExL6DWh{xh+BGU`k^s!7# zKs@q*ix#ph;aNi9Vo82d5Q5OYrNCtE^T5T@7=ne%poz?~6sl)T%m^%0z{PUpT0X<& zr!Na!tRTeA0T(MmL=0T4L|&O4gDtQ#J)xtc_u$#X4vrvo5Y)EptlD@o7;A zSM;WoJ{c)_k75N^tVagrnyxAI2|9S>^aWoGSM;Om^}Xsg`9kti|E0nbL@E##An{um z>0{Xd`{)$^?4vU|4l0OZ18OhfM+i}DNJdVMhA1||Fy>}sG?CeaG_qu~5QR9OKopyj zezSyLFt_?IW0Z=4X@y7|2vHc8L<*MJTyz(}5;f|5z!GJQ$$3#@3$aO^#T$hp_*^aX zpC-90+-wQ;0RXX;SmXeRt%EZyZ84rO2wZmY zND#usqws_dim&0U-VIwrTL+6^&UXWL4FMD8wt^-yL#bO_t0wk}*O=Y}KB$s*4^JDz z2Z>|3@WC)Ls1;flJ{V5wv9jOwDiLLm7L?Besg^sTr3f4t0h-8+q&@n`l(?Hb4HP)A zCmG7RYe-FZ?x^a2FETV) z{qGGSw)&S|ZuP$p^|-_`Juk_dTzWlMa zAi^dB7goxFXd-hEuC>eigPnqL@#EUfr#S>46c_Y|g31^4hv6nNhjWNAm>jm+w6Ob$ z1Sxb}74%1tv&4Q9oUV=(vD{4(h2|&>A_hmJiOeyStaC_gwOfTN=#M4gah|ZPXK|oi z{hsHRs^5>N%*Ne10esf2GNzalK@NvcLW7q@s8c&E{#l1zxqb=>PxXXV&N$D~c@C*^ z{WS74?$GJrvkuAGF;28IFbccRM1${4p=fQlm}%`Ej}%3Lel`imW(f0)Rt5SwWN6&z zbIIol^z*3ue6KrQpkGi%1p_QTxTDX7(q;0x0{tQkARZT^iOeOqrjIaU0^*TZpkGRs z%REb1pkK~U3PKRtcLkWNeZD}y5<{@?Dm0O~nnLxAi5Y=~szASnT-Ro}{PblD^y`GU zxdQ!qh=>dH8)(6e+5&sJy@`4zet|Bhgi>!7;JF&tKQ@ zk&^eQRQ341WKgc@g*b&0P5^eaZXMBl;~GS*hXt=KKxiympNcP4Q)XQ{frpk zO6X_N$BzKvYS%=Sak8uNd5)^-H!pC6CA4^vE}>tA`0mEzH&#KniDOM1$`l zp+4=5*lwK}kK_lsFf$2f$q?pwqR@p|$|&{GKI57Z%_r1tAFS>j@@npGOxK#1Jf8 z2u)-brcga&Vn$%0LKhYx*PL4rGp$-yRmsCqi*P#wep&yy0#kZ=PChP7p98&3EmKC=8sDlL0DOpas z%-j^}usnv59V?)T%!;^rwM;EB$7e?&>aY@}telaO_s~|T!zyG@uIZ{ppUQ*B(W>B! zQHRy2dUdaw2iS6`L&xYr9eWKOm_QHlA6KdeEWC9Dtehc(H_Dbe`D zS{TNRtc@lz>ySngA&WnV%L)FlF6nzG^zzzD0sc_ibJGWc>{&w8ge8?iBGwa)1xQ4V zcPa&msA)nDCec?cQHS+LF$q3L%X}e2z2~{<2P*=sVtp~pVHF#ok6#qR)vlx}BWc(0 zMjTbCVm9Uou?q1nja6)dk=j^=Ot@Ryn@X37)Rjn^&A^U~Yef^8&2dfd0pgM01L~p{ zTTsH583_fb#a3icVbSZ~Y%QO*ErV<>{v-d0fxE{)e=*Q(1IEg?F+{Pg+|3?C6kh}o z#db8oK@{8L2EYBoAuc^pUZ)t=T4P9}4cvD9NKnG{qacYLsiubWdh=@yZQe-)bJn|H z-_BshobQ4rGP}|SakZM*Em6Rp~Fiq#i39UX5Ii zznwD`b^j7T<9Q-g_U_PH1ThQ*O=JeqKKEqiBQkM6c|0hHp@R%%-5*S9y5Ac~hst=1 zfxEk3U@G@YfDTJb2@cQz=dH@sKCDDEU^;>$FTiGEcc;A zq1hjUh{OSCA`?-v&MUFiZY~ZLIFN(~dBUPse{`BV6d=z%g#sK**^Rq*2>7gf1#csz zOfrXp4FNa|4c_6PZXE#e*9O2<{YQ}SNKaU025^VTb4*qJN0Fy-$BqV{bu62H$KW$q ze=Hh&V+R#z>%~}W{dlA=%KYO=ctVCS&vaGhpGbzrO+SfzuFOA~x=-=C(`EjtWmGWC z;)6R-ohDtTv@7#Z#{lAS2Aas6iEH|ZBqkspd1d}tWI5Zjgk}C%eo_#E(7toPWbN~1 z{<#=}h3BD(%=r|mXH3ipEL3Iw1?0Lg!{w(hTjpOR#LboY7eho`=3hb!F4Y#;GxKHC zGx5uOIc=0F^Yto^%X(R=uB?|xx+J<>x~{Ch0{zHbiK|Z>>)uryQqym)7Pk6jy#&iC zxkkFo)Kpo2EryW|*P)5b^|*SqOeHbLXG39Ge*>l5n30nASXE{HO=M86>0`Y<*#^&( zo52^C^|w&)jD9lE5y1H+h& zJJCeuF4D-_%$D@xZc@^ZBmLb8eb;}*@*W7WhX7F#mLsa1zgM&sl=HQ}^)El@Ii>u4 zVud;sH(JW`;mA_Hk>lC@&>EEP4~QYIbbkq9=BP>u^9V;+x{EjI z(*044)Gpm+V%_?EOu9^%Mx$yT2P?Ab2{e&;64&$^7jOI;uUoc1MF~%5BovhG&yYcd zM6Yl2tbE$GK9*~Vvc1xO_c23<4Z>>%qiTJh;&YH!`7N&IpO?EO<7)ngpqhVymbq&F zMcm+LcsRsWCpOiq=8KJqi~N@%)UGNCVYsSPk^c&{*9eu~3R^>0UKPR2j|pe?YmkY= zc^yq;-k@m`m}=sV#0fYc1uFa%4Gg35aFBI^40D~>46 z{+7y`5{VCCKmn@o5lHZY3oR`QghCZQAw!d>!lw{oQ3dJcq6(i;k3$tc$4z9u;1IV7 z*^i5(8bS@?a#&+4sNqY>w@|}Z=vUU%P{TS+XTA9vLb0~LK@*v8ajlI&e1}g(|2SE2 z3zhQLd=H*tSmFmzd065{+(hOl4l%F^N?`X+iF_C`1xx%)&JufPaE$y##B%3M6q;W# zi17S|CNjTMvQA8~)$V%^miU8&e|o~Ub(@|dhgRfytwjqQz6njz;gaasa5)g;KN5DsE1&KJ#e8AOk>{@hF}jndaesS&&-z<3gC_w4T$&UO zzN&*-wM*iGb!j}71(1!&NjOD@FwY-_Y)nap#{HR!d=A-|n!2a)y3@$Uv}IH<_Tqy( zZ%!v&t_p{2OpgJ?V+J&lnGx6YDN;;8Jo1o@naDD;X9&CT%!tdX{GiW(bAi7Yv{`6BACfD;mqCwGLbu5qKV8_G))3i zP27=~A$=0aWoy!I<7s2aCGk5Ka@m#)YHz3uxok)3v9bdfK`tfcs8PtJSfl_A+r!2p z$Ylr6L`J?MFuf>~U?opC1-a}YP zIyPJma@m)J`+34D^MyrEp1%rm*`GX(`+ETRtiL5QI06G)IuH%MK80F!28ajNrSVu6 zfLsnH;UO8qJbx7Aawr)Z_vbM3ImqR3>OR8jPD3t7mQlgjix2KFdX#jzDjei;GzJil zW6(tASX|RnEG8fxd63I-WI5imgpkV#{G=cRp?xQU$=c^3my<9A3r|K9nNuiK&zP7I zSg0VEQ^|E&hRaW17IHaVh?|34&VYy*aygS0oTV+W^~TxM^Zz5rrFch(As1QJ4swwI zyWAQpT?e_GgMMVr#ntDN_4+&xsjM*P3tN52MPlfbTp(R0a0+s{5W`54i_k>oVqCpi zW|)}clcW%Gxr9RVg$Ix$v=E3UVpl6U;3zCV*US75g0IavS>ijUrs_lB_b! zb~Ctxqbj@1og5+LB2K0um%A`h8*-5xaht?A=`!~wAmnm4gd%nCK@*vKaZPVA;-}wY z>OwB}QNsNh2?dbL17uLa(%Xx9P(E#235UKCuefyfA2E1v|Mrn1hw%$FMs%8oz+UZv zBTtO5JdAx4bNzG7fhGdjiCpxznJh)Gi@g@I(C6lTxl`F;5*Px&P{dgTDc%_M!6gjHU zk2lHCB>FKPLM-|rymy@edgqci?~IbLhms)cv2=okl0R^^`?Zpn|~`AKbB`JD6;M96Heh1Bk~YXd*Ky zuIV$En1FcXp%aslWpd9Fq7zf_lLqaZ5=_=Uk4{X5Ay_yyn#fE;p?b!|jKD&LPE1R# z=`vh?`m*T6^g`SmIxz!8#OTC~v|uJ}fjyefOg$4HoschNEcHT2X2r)~ge+SJMo2te zD$OEY2S&__eq?6D)u)eja&``>BrtObTYWG>LgtjrDP3;LDKKI#3?nDzMiZHNaP?}L z@M4b7i9#@9UP_rSBPH+AtH6l)$)H@*)q*}D2hW)Wz!!rNJ*j#@N|K~*>({O1KfI{Y zBK{Ihb@m!ypOoU6eNrYTJ_S82M7STb7%)h@%moZKB7<7OsS{WSlvgAL zg8j;V%z?P3k6B^@;*kdv97L9bJxd4^9Kufu zLJ-<_D448$lXmOYZOE9RgUn$Vf`x~piOdnWrY#gR0t*#Pa3r~o%5eGV%fbXl3vqKW z!7&gK!vx3Dg5$IW_UwH;^-O%2K+Y%SV1i&Dictbtv<@YZaJo!7LAnklI1&BGoP?{N z8|&lA98x)8P7${HD1k)GDLGZTOxG#9b?dhCs1ak#z>ZzbX&6RIoQ@_kXW;79GM~g8 zpAv;A!I_kDRz^zRLsy{$XOls>rt5<`&zP~`i&27esQO&5x^1^^B~b$Th6aNlyd2#z zYBavre?;f-cAmCk$UqKYTl4d6?B}iabB7;@&-VG5903)6a2_ox;ai9woKHqh*c6E? z<^l|3zAi))nTtrn$GW1im52l+!4EDb{Ur(g4&93IgD%I#TnaUb5n(x`kcG>{o&scH za~PUa6QJtts)0F}!{uVJI;S^^Iq+dj%%R~U;uTOGKn_=mH4bvP3Vr+p60UY(RvBEo zC0xT%m0RXoju3JXm(q~Kbr`7)Ib4iS-BxkEbeVY*KKSMa2uA|nh$b>O;hNrX#9zPR z)CD7Mri5EE5(>bGTgjk;rZ*dNn|#V+X7LLQBije=fnNX_HMDaNb36E|Tj87&!w`31 zpz?MML(CY!5O>lD2SeP28~nZzhq#stPLoP+3_#osX1n4fD&dM#0K`4iQp0<_)wYHv z-z$Qd6pfpAA9yk6_oIo-12jP#ttMtm3^45p^za~QAM&(u#hv(<3q3qc2DOswLJyCS zdMr$7Tee&7HWUBXmyWpy9V8G9rHPc`k3we=-0&D^BJ((|>BW&apFC?6-0%b$$~ylf zsp-B@mJ$%Nhp`CJZZP(f*_JS)yU1(^jH!_y$a3oBHv%Y{7O6vpr@8Jffxo`VpJ zF-R{LV|bo=9LDehZX)v{hqyB5=oSPjgcroSu$orz!b=oo;f0scuRN>ag~cE}=TVoF zgXR@5V@17+CNi(#S{qn+9iNJxagyfKbqgFYZ{Xu%OyNyXc}!tEZX)v*hZvU0yQMJ& ziCY*2g(RCL@c+UM4@>XgNVd?Xd?4ICF`^jTkXc;Foh3D_@O6kTfAG@ zs5>+v&pU-Cd_>WWd-pN;talAqWIh2G-2W5}UI?LT?Y?+x-FG;`=Op~X6IMC@JnQHA zrEr8V$!gnP6K0}yix`GgXAVcG( z|42RuA^b$$KYQJ22;rA9Di~(*!5y@Il`a#yM>j$UzhMCJ_#I7T{=hZ8|BDHTM;?Um zCt3dTEFpyOH$N!|L1^DUV6yg2+RZ@-|HBY0{1;7R{=+qGp_ma^s33%H3kp|vT+>{B z`mzv04Wmz@DWir=E!qA;>wS41}Pbtuc5YE7gGq5=fUrQ%Ki= z2UDUSnW@B;^jAzw%^@}WW*T9u4<1OYoRVp!%S26q2h(8~$uK>d$jpGNSIbNib9^!s zf(J8F%1jw4d5=^D9?VPz<(fXv>l1D8Fqs8>F?cX5RnO*CPvBP!#54OiOpa{|BAA_e zOL!1M1apv)(=r9p%6$o_nG?g9mATMFW^U5Rrkedi32{4t2<9REyb1l$&Hr#d}gxTUo79Kydzsr zC=Ckz1;q|m=r4pmevJrMyNId`p52@l;i$?GvnWSc=!-MyLVq!g)GqX8p53xuT)NDk zt_Iiif(RsA3!2C*fopmT5U>0eP`8|4k`k86NGK@hmnMS>jb8p{8Tphayb^U9zH4(8 zvn)8OlXg!E`QASW8*5`HDH*|j2(2-k`# z;a8^o8XoHnuQfDw6%owoZp5%v!G#%K4NYWLr*d(wniwp8W0I5NeGSsC>1pHQJ@M=e zk+6$gRQamc~)>5zv8E0R%i}NMZL2BA{pr@!{Ul%ly=}n6yI9Z32 zonJZJhYV#MUXRptSe7gPonTAr7$2?64I8+T;fq*2r8)3`+)>+iBMya zLzi{OG}?`712QyOrEdr!wn~>?Zk4_f^|&g1W86e$6Ap>3@n6pwov=U`$HLN773iB% z3TMP@hJIx(U7+_Yk!PkAY*;UwqlwHGxYjPsw{#lDb$45MJf~(Wd{SJMZw)G6m2ZQa z$ZX3Yh9N1E?Y<&$3SEDwJI3tXZAZ=$`$}+-+FrzRS4k9_9WaO>w4sU2j+Cs^NNlw` zhO5eVBH_-SP#E)`_NjDs^?06NPj~lz?LwiA`?V|htY4*UF}r~bF84=+7cOv3KMBP{ z>+*};SJrEMuTtbplm%? zVy88He0LgNA>q&rVV>3RfW=u|B}3y@??FCSgb%|_WQKEyNp1^gr=qir3PxCbaEG7~ z(q;a-B77tU5RX04M8@Eno=7nP@yIK}N0DW;X9CXU$zK8K!}?w!Xt=?i|_+!!9m&ro7e|a&%`gn<-Aa; z2$zRuTz<>)bmg~%&}Gjd(*3tP7sjFJN9HhGea2Y74(E`XcXI?r3d(PZl2dY|beW>5 z^7|+ZBMpv56PaUh^=g?zVvbLP!t(oAN;xhgCGUZ$%J1XJpj^}EZ+#jKo*E~BFD}1N zr0SEr>Iqzai)Z$^mmI=W`F%3=mhd1fzfU0}r$v|Fr(zhhavGY*oK70{@<0~W5q6>v23z5T7L6E$@05riBp0( z2kL^t`&_ZW72fBekKYHv)h?eZ!)6!m1sqkmVJ_qd3vY2FU3g!Fk=li~%&=R~7fY9! z)8)eZ5{N*WU5X|$m*JXT{Nj~g{B;ZO%PHZCjD+pG!^WNDlH|;;a%)3#B^gv`^ujk+ z$*24s^AeTTh@qXM`;Q*ceB7 zf=yq$2ul7PJ~w+?Dm#h8_d!oVv41~E@LmQDD)RTT?mh(`B*PULIHr0fuKa`8$bI$B zo=uACRYEx#JZ33p9)b{C>`O1V*nb!w^r~J5KKupn5!^)PQ4Wc%Z9QuSFD(7VO}lt+ z1f$L9o1|wm`Z0Xm%NlPUN58U@F8!B>ntJd`?i83OAP4L5Ni>mp3fJ0Lz|&6UxbARj z_L@$aXFyks3_J@ej|@DAo5(!RA;v5z)a|w=K@B7GP51-~@K;IrnkQ^qp(``tpn^O{pN1Zn0@L zj5BXS0D>|e4PLCE6*?#q0~?eVyE7adWSojl~$ox#9dd9?zz(R#2{6el@GhBZ9vPi;jLfjmZ@H<4r zNWveq;7@IVP4mB~XW}CXa+)cHB;-CHVrW5DuY(pOrY@cSmhQjZnXUhzADRE*>Ql%% z`Y(r6BAEX$QUEPT*qoAX3!%%LO+gFYF^s(EfhIDO;Of;f>BStM7lqKmq?9sQMoQiT zSwRbvlR>$rD-3;_4jwyGfG>s?rljhryz275mg&ln_`d+$foy<%V2Vfffq8y+^mdVp zf)u8vz7m#)kis-%z!YW^ zlN_cnJNo!#9$f9ZsWN_c#m>o5l^kX+ju2B2ztWh(+!(2iDaaJNl{}AhnL3Te*USr6 zD4aY_|;w)OIUysdS)bSFAHQRx#VIA3z9*FM6YzSkbK&%dqRgu#QUs!_-P2vk{LWso|q?d~?tVKQ7VK%VT*Tzj`*5MGBI(juD7$OYf zs9nst2*bLR%2_nM(XY&>5r!H_u>Xs9`UIKGgXsfNSfA^miA-NyYl95^oYrx&Xy&Zr znOPr{#W2GLpz<)ohPa8$MjT@3lB(bCbrRb!JPKymn4Bf{y5PLGiHPM+mnbxwVh};u z3{7NODOsnU*lKqy2QzF=!Yw>u(RYzptlERt$#giRAZb?Or`??kQtgmvG z>&lk5jM*A85Sne!;C&GqqC+E*u%U5a!*(Rx-V;`t8>|EJyi{Pr4&-UvOZg!X>t)>> z-4SGPWG6KEb`9#%j)>jXk@0qI??S>|GlY3wD7axaGBoZ*fATrFVE}cvd);ZcVfQjB z7;*8z9ry-HmwDd!m;rwedHvOC3ygDhc(I7nDsMval~zjm?gg??oA#?@z$^>rT(sa!Do3fm+- za1PMt_V{$lw2;U-CHqO2X`4bE_Qx<%;{Y^~iE#C5DL~BesWD{_bu*Q{8MC{j%G9{Q zQ~W?sVTdTyF!{+fx&7ltBm3@9Dhs0TWcIguWJvYZeP@*O*m1OeW>3y_E9U`ozI6UamD;OC$Z zCx}hzG~Ouszz66;Fr8nOpJPz*q3=YP5C9M-iB*e2Di*-W=;L>4aJ37d$}rjmd@4s( zo|w}(vP2K?i)(2B;&hDE1|Vd%-NHUYy3C@kgxQ=4cBI=`Xd-hquIZ&K9{CMmxgNaX znn&4*l`o5bJG*m@rG#@b5(+?wbIG8>q8Gn8Pd;svf0S+*gs@*O(%)fQ=6p!1E(23z zAmRcHR8Eh9h~)wx;zF9`fQXB5gI|{65Z9s@R6c*wmc(GhB@kyPf zkU_2Vx`4#Bq#g@X+WIszFCLVb0O=+r`gO3Y2$;AYG?BT19!M~=0ZN`Z3YfT&3}pj! z6R8=X0SHh4OxQ2kaX@>Qz=?Ezw^aIx_cudn0YGsJNbtT4tt)a~0Tj29p-F(^b_lTm zh4gX(iaV&s0Tg%QCNg(%h+Dv71(6Iv3UM~9!f%r0W1kM=DA|G(ccWkFr$GvN{idt? zjkyQnux{@~6Pf#PtqoM%?=+8-#WZh$hvorL7lRcKg35yx58);<4|9lNOt1sH7fPJN zFe$L&5ptH;3xlKLqav0&VWQAHhCu}8aWs*6f|7L_imi4xb6~}jBz(#fw#gBztJC5D zi#&f7VDU7SHSX^-;IsZVWuti(auA~D(BM@T8lyub5wRh1pv4O$e9;qDnIkME@;p_b z#Y^OA+|!rAXFV;<*H=IaXI@2vZ||T!?TpxNof(hx$7$|$626fk%=1J67jKfGaZkpR z&jA;2QTN+kcUuqSTE{@QTfD>Z0u_w9_}~tT?@E_zz{)c3VF2-XA5COFz%_mJ6B7`R zJmBI(vV7!OLg3ESK^m-BsnN&J*WhX=tjaLjg*z=rRgReHI6}}u+)INN(_^GIXdyH07W53#Wd=1G zW-}vLvFK+)6PcNDO)ppR#xMH1fW<77Fl$Ca0bns38B|F0f;Y3vrzOAoz_btAYmk`( z9M#FN>SJJHP7G99V_;&n0GODI>K!mKH*WANGaTZ^v3UIxDK*9b#Jpg$t3@Iat`-GA z%t!e(Jl0!WYiR8JBAC0zRttDm4fdq7?rLvlMv?K%-fB{Q^1n;>}W06A&3|NK?O@aZ-LWl(e zq?Zc@EJr;K3|JmFky(L5Ty`^Kf&r^AI$_~2j)fJiD*RWZ6kGVOgnnf;UHJDbv7XJ! zV8eP@1x;jD#kF>Uznar9PLf#8QnA%$b$n7>%&!3|U(BzGo5-xiA%-ETt?j-daSB~m z#r)djEU~WyN2hf}EO(Vep;;G$2tsc(k?BLpI*r6uyJNUwemxTQ^@ME;mI$>g+VlKU zMSDLAZQQT*!Dsy{WsBJW^l*7YG^36=Npr76Hi#>obQNKsOEX3it|m$ z)3`^QfzNuB%C%Mu!|=_~;JZ2~TN^HRTEoY~HWcDpl5ndGVV>2h5Z{^%ja$79`CK8s zEp>0_b*BsQ?aQcOgvAGU_}M|a%wL>Hv#+9_1en3xe*s0#7j$u%&;<)<%Ohz}Ct<_hr+ zh=>dE!L(qAw!ofmE7UXb3-PjFePGW3lbMdeLkDqrx`JCm=(1<1bX~z+ML#loh!g2= z9vsFYHScD)u+=ZPB}z_7r*xU3se*e1hLHv%(L`oXT)kT6keK7sps?UJlrkzKCGUZ$ z3hvQlP_F6ow?2&qPmM9)iwo|(sCsX&dIEp-fp})0d&wb872f+$ZwU{=!h2sba$0oZ zy&r}#EBm8~%mJj4#hER<#qFf_R%k@!jeK2;0KG=f&#q8o0(nt z=D|b68g=Szv=HZml7)EB5~l=nDAWZ7_hDjzE4U9wA3p?xt6e@-hRtqBM{-oPwhb3Cr;#V=m@#b3AZK7kTW%t$CG zyiX#73XNX)=4AP_tuLmhOr_O1XvFaTgYW|+1LdbjRu}}3boZgdhK}A>&{BL0!YPne zT_1}mF3L~EK;`kcDDNE<<)?}A_*)Q8#|?heg+pA2eT#CYz?!&VKNBMD>XHbCt4kH^ zXHj>JNa-!IHFV@`5zI8{JAsTI3yH{@bI?TQTwGnwC(cN`kT^*(e;#Si_q1^_pLm^H z%wIqTwaV)j^B0nOtn8EPH|we|^!rYj^pleLBG^|10$dE5$Xr5C^l>Z+RPy{$Ai$+$ zC>yBDNXo~qWzm6xq;IL*Bw@H5+6$0_D?ox5QfOvT6cloB z6&adD4z7j}iyTNV7dg0wdK_|aEp8%n9f!C#ELkR`A*3K4hjq1r6t1Uu3n|=ye&r?& zDXi6GwwoIv5-a*9G?BR(*V=HyEl&G5S!N5Can;-kmSP;@Hc)vS;&$9b<_-=qs0l1! zw@Zn77%zoG+)2(7+huT~yi3G#vrH74aTr8&?nV=tdnj2arPyjWJBLHuOTzm+VbMQT znf8K(<1mUmpA|-NKNU9a^8?_sJ{SD+SFxSuLC8X=9zuh6LTHc#Tw~vF*dRs1ep8!2PdJ+x3c!Wx|N8*6>XgrJtu<o%kCC zK=`C30MhjF@gJBHfFu7C>l`@pFZ%e28(dwX$gtW4-fa;XRrzDObA;fCxR?ey_ z;D}^_TlkZJ&@TLD!fqyo7^LH5Xd*K?uIY_JJo6hxU4Uc?N|-Vup#UJ6iVP||dXq3y z%cuOesL}w*NHbz&`w;#*E56TRSbL0)OaoEX1+da$bYxl#R1S*Kk&Oa$WIEdAURjtP zH~7^W4so&e#^S5<60Li1)G#H6MrMROyY?h@;o4Ks$V^mRBSv~7Z4JGcSp;(nnjjX> z0&z%|SwKOE;2i5=kT;KE|R#Mi;K)j2DSM03bHP%uXmV>)MI5E zU9YK`@t}x=tJ#zjC}3__R)mPm1DeRpOCR((E(uZcU{Z+4d}JsaqWMY95DkQH9ue6x zSuXu#wKNWg)X4Id$_x^K1)#S83+V|GyfZ@si~Ltu$U{y<9A05$bVR z$fCH3%winkPSC3`m?01%?uLcE0zww2Yzu_+LccPD20{wnjIY1(m=?&x`dtD|WR}FW zHVU$oQ$0==)%=A{nx#Qs41p{IDi47yi<`(S$05ctK_u+9D8UXRr67>y$ys7s49=G; zh*)lli9)j?1`(Q-&_rfsO4hk3w%UEoK_IJ;a8*xO^kud6XU5?lc@8W5V>N1P+~L*1 zXB{s1M%@A<%^DDdAgzf8@6ga19VCf~4Uz*t)+XUPp0LU+VFi-ssscaOB~Rn7_6DDI zwM5SL0WsWJ4-LKzg&MUxV!d@|JQe|vkA5UvKSP-3i$Xp&AVcH6Y)C$bd~8JB8++Yp zk38(;rtqQP$xB z98w8k+J&t?>>=TEN_Lknb2kNh48$<%dhl2p3ceWjs8aPFUUgd=Cax6hp{9)0PYV9XJ?uFcM7*^R+vK#VV31+7 zrG!@@3^JUIoGJ~2bYd7YH3Cg!Mv{hS07YXD0TPM?2HBJJCZXR7fvFFJbRi;U6ci-t z!_rK_BBRBU0$4;KtDIsHut?*k<-jCk#8y=XGzydOnM|0Zxx?jNup_`o_7>9|MzRn3 z_yrEo9Mk4;DF_Hr?QX3ZjsW{5*v)dgSWP}htYE;$zB?3$FYg=3jqvCV zxHWX*coEEenGgn_0BJ~*6VXKGBpM~bs3wj`oRBFAT5>XJPw})dT9SC2i92DJy& zMN3X2^;jwF`s8m-@psD9pBE37l>6?9y21o1I30EsVI^mPCNgKz1ASIc0+c+x6jpK; z8OjFeY*I5o?FdjFRtn3vm;fi#WtRVDX|*hCqpU8D)bciG(Hbf32xs!x8W ziWz~03L|-uTrXv~ z{Pblpl9z?JIgI2Lh=?(gS82g(+5%f7yiPq6A0v@7Q5P|iWE+Sf5?RX*B9YL#ta?Mb z4kCFI{m6{R)z6dl_bm>od@yedTYZQ`qUV&nBVDF$3L<$I!$^(I`L@DsYe1T!i)0b!>^A&0M^j9?Y@h^c$0Ftjs z|4l-_1;SDqASo9Q^DV?D%EMAj!6V;^9R={n1~9M?9w}v54mk3?SgOwbje;Y57MJ-p zi@FCF^8?HXu#q3dGKY=)gg$;#30J!qs|>K+27ckF$}96LM~IDxdueRsH;mNAMkG7j z_VBxOnROFx0?Z!}ilqG$O=SMUHNClrpMG%tK6>MA4SkqgR4`p8fW1>d7}8`)G?AH# zHc2R|i60UrWJ-dJOikKpJZ+4OBo5~yBh!*WZ2)zVk?BZ17N+o>qpr@12S%DtH30^u zhgC(m$PA!~%#5^OpU;!@w4ShMq^iOd4H*2YA7I>qB;A-Qij+?xLa zl9MTBK~NV%A`5}aLm~^~CNhg~h*3-s3cC$Tn8PS3NMuoRme>Y^^XFnBmYZOr&@7HY z1g007$h1(h&O))(?qm)US%QR1dP4s6br-i9hlu34s}PZ;sH<^zmj<78w;Y<5yN;JJ z%RmeQv@9CD?n7I2fFvF^Kn@UDo`frS!YVU_)k&VC3J_V5JdHcL68Nm6h1t3?Na4&X zXz;x?)Tf;h+pRO>k^I0zRwLo+8NxhI6dtk$85;LwP4YQBWG(7m+v`r_A?uV;!KjN5 z?$o%hbh!c?9?}~Fh({kZky#Jd^odVQKs@sBkiKN;=UGBLWPN^85Q5OY4ZvjWn-qH; z-x=8uL$GioG?CeuLiLP^8G(fg57~rVn`XHD^kwmo&4jo)JfsyOVmxGXTCjz-z!nBu zQqRQ4LwX~S4d5ZUn?MYQ$Vzr_h(y*U)mGAVaLCr^M`jybeIi+Rx8;yZ2eX~9)rUhQ zcuvXo(q-nR;E)|KjO=Jb6PX=x^=g?~Vvf&_LO5h6O4&IhCGVlF;E-L&pj^{ci$0YH zkE30|7sDaDQFVW>dLsOzjCf}ss>xYW0U!gYyMz}Z0MbrIPK^RL%mnL(tH zb({T18F4)UKsrc2IHB)@{H+gw6#sY105b#v?b$-qg(a4PJSw8O0P?8uIPK~`$_y2Y z)FHl6kb}=xf*j2p5Ua2vz&Q30!yLvj41N5N6RviJRT)vcwmUhhQpb$o2r&-vE{$=F z#7J$7LlVHP`8}n}#A+tu#y|`*aTJ=!jK(#+M~G*BkEn}kjG=_RG7<_Jo9^q+YU?Xuk7uYzG3~JHW1vZW%^;p?H4kT|pdYP_~6Q&P2bmsD?Po{q4Ti26z_aVf~(sCNg7jtqpRV<5Z86MKyn+ zljdB|7sDLqfy%=i=i??a7jTHNOi%~AElRM%NGX`(LUNYa7K3x;MIx4)VxrJoj6sCv z5;T#yl#+EWimi5Eb1=tcB)r@cmiz~q8Z+a7jy#7I&~XK|HSX}0;Ij^w`v;j?Mw+W2 z2tm3U4PM!yH9ANV6B{H4bzDor>pWqVS;ERA&s7C=Tu+|HUA+N(*3}X@dn1V9&P{0W ztvS@F-4W}pJL9nk0CwC$!do+hdA=yH<2Euh?#u1ub703E)P1Mdod!GZDx-pN7a!d5 zah!Cy4jkBVHwF-od(cGYUR=`$K`{aG$OAj>Bg_4sB?LPj;3owk2<>|iOx8XRc07b3 zSokoS$UH)!dd9?zz(NIfJW8&|GF*Q8vS7#KLfjnK@dQM~V8@fR;3;i^tq`83o{0~3 z$mysdup{@;9>X27njPFBv2|(njC38`@htk0c@9^fO4i}$IiwQ8ydZ4#;SLF(Q}Uv8 znY$^t<0T9uKVC)?nOAW2YMESOj?a%mxZ_nyc`YL)?*Xphj@QYcT+`)@KCK6jr8mGA z!yRu@^?0v(BETKuoqf0_r%MHQyhYt5ya?frx5>z<(QwB*7{<)JizYJfkw#W-7VZ$& z6S(7j(tnW9_dy0X4|jYBf%c3c>cY}X!5tro=Kou`<72T%9qSu~JNS%k;2&OUJnhXV zupuW=0N=&%0I zs=vHR$0VSM z%%rqmAKH@eBo875b4*5tvf-JW)C^DZ4#$uV^`D{sy~on;aMbj?r7}XCp8`4yAdV?P zf>(iPT#@ez;+UEYO+p;gK!}Anq?ZeEOiMiu;+PIMk(r)DT>a=dh$BCcA;2NdhGn|~ zIA)+^3vkScer1FPIEo?qn$uxsf;6nznbAaM7F=t?8?!pa<76Qve-+Pn(98zvVsK-2 zPv%o1quH8|9# zoe|ruGvkr`fHjsP;nEqxJWmv?u?!g+_heb}Iap&k>R#UKPQw~2lu^N`ix2LQxT18q z0vxQd5(W^DmC;0I6=Y>2B*BO6pzS>7@abWY9neIkjWm4nD;oRgmp~*C z$Bv}mDWRVj|I)HE#3#zb@=F08yNDeHfX4<{ZaIZV`WrvG`Y$cJilyqf-zfaSCvnNQ zJ!)LNz0y01DZI3@TW9Uopev)3z1h zZkZBwbVvUVV@4PUe+&n6bxRy^Vg#fU1C_U81Y~4@fQ+Ce4gnd78~mCUhq#8thMbg7 zPM2xrG3sF;!7e+APq^$9>M@F{YQ#bBudSioqeU>&qKh_;fdHhyUT7k-H|-FYtBLIr z4P-%rbnHXgeLZcAbRgxCCZ9tcuA%O0z3w#Xa9tS{47K>+PG{Fkm+9?LhZ`_} zc-)94GB@FxPHiy(@yJ6RZYIkuo+U&bZsjKhAqefe4NTTPk2>6rAy{|^n#kNqp?b!| zjKD&LI^0FBaTzW@eOc7uZXs?Cb+`v2V$|VYT5zAXz#hQwr=E$AI>@P{9O{sM_Qptq zELn#%NHkp{Js@3&G(3oYWFErRCy#aUVGgMjFpmgZeWXDG=9D}tU1n`7kyvd_olbf-{-=c%=X{UNIG0vS0e3NbJ*Vi6}b$vIlK~$nBEM*je@Ve+MKoDw_DnJnG8Ikh^ z7;lJG>L}ePTENF9(Sk+~a&JO&fDnuqV;n;87W(-0DqQUvsxp3d^}fSVl_KU{ju0Ub zkJ1Ridl;#W5XeNkRsFtnnLu5OulWE1kZT{JiOfg1rq{pt)G~i=O_#`8t01fz* z3@R{s?VHc!Q@&?g0uAUG*fDgkj{d`jjvAdp1wMz6%2zQY@P*t>7efO31dza&G{-># zU*QJ7HN_z=z@m3)YgiCN1K&WBT~89Ma6Kt#;9IJ!5fr^4wubh9CxV#|P1^cB1R*be zKoglCX^(`Un)o2mL24ur!B3?9+0(`lLE>yKMDPn4)Pk-H5&TN(u~Hwch3&0g9ad{L zJX9bd>Uv&DG5s5?DS`}s2Tf%Dpxyegm4qdEs3^$bPcoDZ%U`5sSayI{0vTBMH^XX3 zo@XUrfT$661+o0ql$c12*ST)Xc9sA4?--0AiZ1!q1)oJ&p8C4 zJ8mM=gF{^93)Kl=2qcK3VdboVgh?pX0tu6%U)fg!2`hFjfz4!)gta+2n#fFnYi&Sb zN~d(3ESNd#IA*2-WihTWHK;tUFb!@ZGcAW0xyhkG;|dbmFgglXn2ww!wz=TkH@%4E zCYLBQGhh%wnGsE7W};-Bd19;GtsJf}GYMz$goTJ>jYZ+`g*;akzA!8GH16tb;Ipn4 z0iw0cGqXbk0y761yq!WjbYLV7HZTrnn2UsSd%`L+gVjKulL}{;hdhltIWPFElXWw6 zK9IqY`O)C}TBu7qB6eFx##^|dCkYqK5axNI;D&|B(6|>1lh45oi%|EXUUwR9Sgec+ zMqGSwN4>?R%dB^BLoW;<9xZ4hvjnc`qnnt3c;vwiOOjR66x>i_@yD=(tY8N_NK{=ytu9>$JFJ0zWY)yhCy{k^Ee@$vFl!52eb_+) z=aj4?U1n_xc32m~$c)}-BGU&~ua;>g=J?DggdNtSl)f1$c@Jj=JM<%ia!r>W`jj0! ze%1$H3_EN<)f;-%6BKq3zwF~PIUy?8VIyiSVSflaY)nQ@$`r^jhmx30FpN3b6is9{ zBaN)q?Ehf*rOJThwv9QP_b`QNj*g zJ@#!43j+9I8!^hk58I-TpOC`UuB9sDXjk#}995}ecHju%2k|ToKeS<_HvAwH?pF7X z(q$rb5q{VS0+4e%qlwHexTg03@yYK4b>W9yDPgyagaY`XKN(bD^d4Xa$fs=r6O}0w z2ld}`OvjiG(+;l6?=jx6yWA}m;|&J~c*8*IcX-1f+~7x^IK-7#1W)KSB2z4f(*23JHdXS`A4hJq7QT}2a_J!pV9Sxt-<|1sMMqA-lK!#!<` zC?wwHA_|>kP;0d=qA-HgV`ZmX8Z%uNQHbO1A%q5VL(1oo&{u>R>_dho zae;jy#Nq+GkqeU#YoJ65H27`#hv1lT593|_75?k$7;>!KwNqB-MY{UO-m0Ihr zzR&Yb)%Pb-aO1w61U~CqX?x7c;DPI>put-mRIFVWPp#{&pg)a-r+dOG=bq>6Jg-zi ze+GFP_v%dWS+ByhI}4w{_OsF8>qsbG+b*VB+s7km@yftCBs@1mm}j`E;m;#OW92){;yl9cLjLBk6#nuQE7mE^ock2(U%;| zRH^EY%+&Bd1~tBvM?eKZ;?@#A9e8^Ehc_QMM@>YnQm1lg-XdC08) zhCq(T<|znB#D`^uD$t)6O$7ydul(mQ-V4a8&UqW)8L>s3cpELt`7C5vUit|3EK~+{ z_;X@~tHYm1A3sxst6d&dhRZI@7dfi(z`Vo}*5Tqxx(*r% zSHXrfdJRovUdJ`Ppv4ovpzBuOZ&1RU83_f|_jod>aOlNs-jYw-1T861eVg|7{(BD{ zJhcDt_RjVpc%|fRa92KytMGT^Zi=`HKRT$w-=!U{3V#nb_#Gh*aZwfFHKFRb8vg(y z>@tz?gv&%#;~!F2jWFmvtu-|KBN5Db@2Zg>LjqFZ6Euy-2eKfk%0DCR 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�B0p={ZTi*vMwc;yxCpC^~993*+ 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 Iw$zOIKg*KqzW@LL literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.omf.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.omf.doctree new file mode 100644 index 0000000000000000000000000000000000000000..ee74928bc76e062a91da170e3070f9821cf10d74 GIT binary patch literal 373627 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

    (TuNm{M*JYkAB|G`O$uKc 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.doctree new file mode 100644 index 0000000000000000000000000000000000000000..6f56c3180c07d740b0065fd9e5ca5e254bc4fe14 GIT binary patch literal 143676 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.ns3.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.ns3.doctree new file mode 100644 index 0000000000000000000000000000000000000000..397fa8bdba805b292113c67325d220569716cb4f GIT binary patch literal 16927 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.util.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.util.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d114ec2dfc1bcf990daa827cfeedd07cfad85164 GIT binary patch literal 315318 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.util.parsers.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.util.parsers.doctree new file mode 100644 index 0000000000000000000000000000000000000000..c281d945c1406c19a2be248045c23fe53b68b1e7 GIT binary patch literal 15545 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/environment.pickle b/doc/sphinx/_build/doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..b277fb630b2daa1e9e027d50bb64e3fbdb31ab8f GIT binary patch literal 3275437 zcmb?^2Y6#g)plqhB$Nnyca4_2D1 z`&-mrU1_fN4?lO%T5gO*A9SzM?p}4hd$p72uGv^#Xe~E;-K+b7gMMrI@NxcZwYJin zTWxhmTlN0o-D{lkknW-NYIUBm`mNP!_3&PkKfdP0mri#No1eQ`Yqj4b`|K)4Hma@F z{rvDYt#z-pK6kZRr_()ra_-R9N^OxJcf=9^uf1f(UuS;q(0;2AGOoMcz23=tw;XcF zA=TyDT6@qxb+y@PRjAo(52)VkRhC<;gM*cNeYJaJz0t0N+FoU~-Dvg>HxP$+ug}0o zt#@y5^4ztkcEFD7-f-@axx;JyKDFiteSXf3*1I=8dG4^rpaWui-J4uIcg^~8t=Hq9 zkG^>Bu=!ejA2k$KPF}jn#Y;zDymZrxmyWr3iD$aR z^SkxZu?8(S6`96ucpA4|@7@m6z@vwLxw3S^(yf^Er4yGx>hT+pT3K!OS9{%44Z*ix z@17+uIT|dMkbNeTeb#z+8_3?|kUKE(w-3Z`DH7kP^=p+5wV7Lct<^=t zt7jY1@3`K*laPMrEa`V)(t&75&malmcV)uww%)xv2;bCzbC~Qq2C|PSk{v{>y|U09 zF$ABx-rX()k7fxTV}gNISZl@*QpcIp^VYjNK)!-QX(@h8Woc5Yc|HwI8YvrOvTdiO$*n*4DO z6L*0j&db?eX5JwSx!OCUdyyghp6lIv3E}t7F671eg=7p_$onvL)%EUuOBOQzYK>{V zXIRJ+%Xho8Tx0QCuFY3K?z|zlzTRyJxy>xO3rsFh3;V9ngz!Zsd}+Pg0^yq;bO}$P z9;UFRdzmR<(OZLG$*@7fwuQA#8Tkqb#gzR*{1DNbVAp6F})ovba!q~P~yX%J72d;M? zB*Z>AOYB3KSm2m7mhnR3Lz%>ft#=;|5{G>4QYP$yfv_RAf*GLVZTMw|$VaSqA1OpW zDof;}naGUdkFbQ`$1uT)jWCtPQ^ULMHNAfyg0hN+i?R(-#?XU%cLZiIDr!EV(aZax)r7p$XwHXTo2x z-hCwq-}InY@f2PhrjWQ@1tZ>lwITgA>)qE1>95O@{(2@|JgEYTko*QF`Hkz{H-Y30 zzx-w<^)-Ri>le7O0%y8=xuNeZ>)p2seQ(Rs_jaZa5JtQ)RET;96ZOvZ?z=!#{u}RR zO5PGExn4wxH^uKUbi8-H`#z!L{aHFbz;s;Q(b4@NKl(%K-4El@^5IALY3~hBOXiKm z?S9le?_=xTkIVBuk$v7L<9TDK%==UP@K3LIKcnWYzVTV6)kI1kzdRb`6VV2=$k2Y-#H_W3ZiL=J*~ zX}$R?%v8R<-u;G5<(t{5e2b?dtX)76(!b55e`me>U68)vm%qoPem#(y*gAPg_xpy( zAFOwOC`A4!OXQE4NHJnEUda0illRm0?$1Epkgxrm3Hw1H?6@L(6tqC4!|_G;7ly`P zu6KVWH2zPP#$PjyfHXXjgA#Io!{q*Uz56?mySWj+XUcyWD8Ffua_EN&hpjzM5_JDy zDE{Mm_fJCcpR*MIg((JU_|{o8u?@1S(}H~+yD{!u6#%pKlnuhclWfb9Qs zz5B0|=dRZ4H`crVKA95*tL;_xh?~p3_3r<2n87;9h9Uo%JEF68JOAt4A(zb^w%A-X zf1^XLa>yZ<;6M2I&|b4f^(DFres{m{=YzRJ9WGs!|8nwD5zuF0mfQ8(a`W)&EY((f z%QZM&Q`A1Vb~s&)#}&S{vbNal_mOmEjtl9(KYy^%N|09^8a0eKVO0m zE~RVYva9_2RaHr@7?BkMcBMDWR^3l{Jep{%umaF`Y zPK#~?y#C%pnWB|uf2rNLEaw|pzl1pN)ubC^#MVpflTY>t=Gi5(J>f&Q9O7e z9UOePg~p)K=?_*{o6D66|7u;Su}P;#|u= z1B*j9Hw)pG|8D+I(E?c7n?!9Q1~+U|akCi1r_=l?OCl51Sz4o8*g4@Ll83x(?-?mD zr%o#TuUcPjagwjHd)N4O`_o{xH<<6$IfdDzV}UlJ$UoCV1s3ttR;FG4bXRQ^LRn#b z0lw@nv}uKI39R+KNAP&FRh~aLke+&PrBGNalBdYZx} z^r=>FR#=hOn7^T z+G#`rD^*=suI=Yy1Kk>cT4UcOg~N0_cy+~!SCxGNwk%xxsMM(m#e)gbN{?=nn_Y=$ z@PcovfF?xSmj+uVFt(yJnnvDpJN~0 z&VrSxsmumU7jz5Pg{r-Njrz?7Re+{VkObC7YB?5IWQ(x`wmi@LP;2n?8my#F#aJz& zdTg(^1QXR`^Tm?Qy1mbf!tB{!qTAcCT1v!*`u+0Nq<*bq?Zzzsu)noX?XPtVA1u;o z0NT2@upFnP%L_hm$)^g{8v7g27t{EGP6vikh8ebu$FB^y#Af}FDpXpZ1}k3E(isNL z*`>@r^NJ2L%$4Q#A}=nT379L26U*2+Yi7CNhQv#!+1zKBYWw!dDg3g(w%lsOhV?7} zAE}gLCLpt@{d%V{Sn1FzVE>F(kANnO2L>dgPM6v%O}a}K=On+9C8~hcTieJY-4)|6FRo99 z4zJ}B=czLwX8XGVN2|)adm{3T!NuXFYNyTi(=h|&dKZ5W7p8c zM|Sn5O{g?#*DDG(G9Hl~8>lgJ3$(y&Ew$VGsw@2gjak5W15QX+%`uy@(ll--645f6 zj*L~$LhB%ROHi*@U2gM#M5M>@`E;*0!Jk@@J`d1}&2F7S+i61dobJI-@b}w2+L2Cc zq!fV-8pl*@8y6ak>C`?)RBR;28@zb?B2RcHfORyL2}hcB)-oI^w$PQb-P&t*`6|Xk zW}l`uzsx?v`M}aXLq1wPcd2lE(_CbBVViJ)oqIu*T~Ipx%_{Tya(flthqXKt zc#0N_8~8^UEe8k6crCOGU%h;YA-AzduO)VaHP1}=&59^Z0_LKkYTPViSo2A{?c&7z zezGS!NT1?b_S%DioWgi-AjL}yBOO!njG|bb?txMJ+zN!RPp~Vaix6 z{>M&Jqt5x6p!Indk?3FtYLp|w@CTX$w6fSY^00v<4h1>3pbHHdZt29a4PPr0H7J69 zt+$W%*m=Y|p7Bb>_XBQghiPxn|DbZQEgg;g30=rdq#RBTg+=?ek-n6PI*j&P5Ic3v*wfB$A)uT`zzk zLuJIy{TkFN)ht~FF3UvacEd_N2t=;li|EljP`4@vDdVqtBCRY1sp96z_P!?7(fAg@rXbTdCeYcFlvY6T6M{Z@Tnj}|ecsJz8`Bphm;MP6CsDw>#tmH?56=w1DT z1BMgPP5J`V0`94CYEN>C8#A~GVd)Y;Xz!=Q5;Nh*Chf~kt(8s2OIyZsJ|I{Dh-S8o zki!Kp&ml+g#VX)*d~tfZC^?V5vOx6?G8_x7MfL=!og$T|1U6ynxB^q(XR;2eK+(Zt zv_;LVV%CP#Iiy-;k!4S(3lyz|L}UX?`dvxt1W;$(d9Z}(H@JwxRX8F*Y7WgPwv0|% zB$*)fQo1s`>$GFg)vz#;3oOxSA8NDiX|q0)D0r3YZ_9||>tj2UpViCjJJWkvow!eOh!*X^`oN9Vkh zmtqCXTLt^N%)++7nO|3><7M0B{(!uRE8fuq0k70+h9&$4gm_Vl4*#9Y6n%P7N~=Us zVLP4VoaO5gXK~qp9*m(%Vls?iSrd&a*3X~9Pf61FA%N0qO0a^ODhp~3)LQ-O0#|{0 zToI>-0!!(ZbXQ=p8GR7e&u?d`C)pnN|#~O<*~ji&6)Wk?*t-0SK>|g@Db@GrCzr29wIOm zeyh%}*}U%~fvNZM{(frmZPnA!>JO@P+L@=Fw#t4>6}96kwc87vRUP8g?CcMwF=mp- z?B*fUc0|^>c@#)e(pMUf#w`i16`{n~KRR7IDZz%d^D`DRJ!A4AqdRA|@4j$sdTf*) zW7n(T@oR42LOH66Gvgzn_D7G!K*bH^p=PJWH7O3Gn4wswAgG$+Pds0k$m4NB;!!Gu;z2o@i_x4%F6c1;UqoT#wRIfZ?-l zH}Mm-ixqc6&{Oe6AIwWQ5g1EahAOk18**zqx_fero`#W0v@N_D=9E>1mfKB>Opl%p zD6Qi&g+aH{F1h&(jJe3IQfW=a7bg*rSck)EDlSp-M>FOldM2QbjP>2Qe#MHji0!;V zimiNNyPlQKOG50h#Qqr~yUv=M)VwqV(X#=T>BY&clwEP>Khkpy6>gB!A&e6K`2BcFq>4y<)Zh^D(;Uo*nIX zO)CY$Qqv1CqL>>v-;eNn;9cBQs?Ba|M+rGTF3}>lXX0UcA)c|X=-_9J0GuW+AHv`5 zRnMxPS#i$q4%;rnM|4dShi|i^7Xes@sA50^={|@l@8fV0G<-FBvBgY!yGnqC+-*f- zUGs?$`;wGc;rc+V<37HjG;9(MtiQRYOKN-F9(6P?qVe_3Euw)n;m|gF&l7 zF9UL7h%)}5rL^G6F_j$#d3j2n)Hnkeu@G+=O z9cy5EJ?;i*R`)XpReNha^x)F#fvJ_Iuv@b9I=xA6Na!i`>fO}xRh=FSXLY5wNN)t7 zPD6=x*?84mv(cLXl6Vm%Dl_JNG^mC8N*ZNga)W+H7T+qNJVC6kOGsQr}WG`h%o zba^^?QF3AOeoqq9&VPXK(Wv&h;!SVKE<&l$GDrA6uHoH8=8MeOoi@D{k4V~xHmmJ8 zdBHw4y$v8*8K0ACmWaGoXaAX8`{3EKLyk=U&Z+%pj<^q`T0(CJZqjj<3G++W6WK^- z+#2)_yPR>7MX)@=Cb~UM)B8Jtr6o?pcoX}~(R6c>t0b&nqGa2pBfg{K*9UXd~U4g^+yWVfOZ10te9k{)xGw9R%fuwozhMt13*@h?S z1Ng3w<<#**?)`1^IT@l4nh7~)IpYe&o3d}Pdiu88-+pE3ekBP6`Vi237?$x{g8G3W zW^DdHDmU_MnWyQ)zjd+I{kL8!U)VN`kHBMZ>;S&fof2`#rF|C>0Z<(oD zL8~-<6r+>G*p@tHJW&(*nT96%7>4>tE+eQ|a{h<>C!dz^i3OxRr}$TwfufHal%nsQ z3E0c#5lk+;vmSlI&M4L*(rjKlB8T0x31s>thMnygD8tciHq4MgkdY_}a{MVflgM!> zUzEsXX=}whPJQ~cg^K4;p1i>VCuCun18JX0NXx)krZ$~h)&()f)SPm#ze_g!vw+jG zE0KKA9%U|ItXXXZiarNG?Fh=+Z43ww2=VskQ>>EH7+y*9n)@t$oxXtKUi8I%3`EF- zDmeOK?jGXP5;`-(okb>L;F!|*Bt&1v7%z~S4MvaOWlIq| z)kacdx7xBpfc17rhBC0EpKs#!8m(k~-fsgbSu*jVJ%mrl_&~K51*!aVNK<_W zcseTGUN&XV?x6x^CayIon@v~N|1O|)pd)e^=yaf&fS2_OeGeEq+Lda1!0;Iy|A{Q% zd0f=wTyJG$SHJCkrtbrCq-gOnEyb4QH#KS7XUG!bkkL*liGd5DTw=rVE&Mu!Z&*g7wv5o&RfHgZyX@3*! z41+;95kx-$P$oH>$&_M`C7G7X{h8}@_>hr1V@p3xXD^OO*o7kN(9g^;xBTUD<(l5i zQu#s+d-hdFBK%?AjchDR(>3=ZX8}(9u9*Otp$T7|%*C&4p@(5{0s*bT`kk8*^> z=P&;Tpd*VCm`Q(Zf?b_DH`kQX-vO-U=)X<)t+YAq(&Nr;ma%^TKB?_w65o+L$iX?B znB#)<`0lyMQTnGPv>+4Wdj^(vNZ?7y4sfMO=LhItfP0bK(vpDF^Yr{+nfnQmz>U-Z z{Tm3LvBmxsV_Z`pbX`(>vfuVu)%h?a`icJ+5Wgt2OO+ZO$^2R72q&$a{-*zAmnfrf zozy$0YolIsF3_?PKjf-Rt9HdQ+A`Q5JcC6#9Cw=Xy?rd%a^#7w0@(RDFLQn>&;d2N zyQ$LN-{TZ*KU@*A`@)$id=PpZ|DKP(bN@x!^LuqXOXVfcO&>L!Y*#>r0&Nc#mkiJK=o;xHG8-9B0=>+O#Wd=< z=EIQWI5eSGLYyF*oG9@*c-v}?>^AZ^QAl!40O<~PK{6_ryZKrR?d1lVZg!1K?i}Ae zF^c2-#;Qr67V0GlW>UwO9*HD=vu%_g0BoWIr*|4 zJyLIb>?JO)UR@cVn48%_hXXDtrH-V#95fmON4cvBcW@|b;58WlKJa=3uyycNYAi}^ zZ_=4@ZJ=snA+;;NjJ5?SQk3RWgiv#$>i|S`Ig0WO7jFoIt^%})-3@{2 z^#D|o{t6WNJq^*X4t(vgts{Y@wdBcuLjzH{ESA->*SEA3tekLdASb9q>*xn9cwr%3 zcoZOYEk=B%KvG#Kvamuo$kHS>Ghle?5=nw&qKSZRXrYqsi7~%M9wII@6?A@>DeLSt(RsA=?)0FBzHhq|t5RqLv8iTevhvtU<`vrG|Zi;Wc+I=hI%DZ@2^(Au+*B&W9 z27|Tv%WT}0(N?I`yX(qs2JpmFJjPEXFh;b>baM>yK3J(&nO7s`Vt`u!Kr0c6s*SOc zR^L5s;`3v(OML%KgO0^8)!mtit$c1F2|n4HG&!ifB|!9YW_CnrLiS@NGT2`0(-up9 zRP>P2%_hXM)#E#K__YG4b8+hGIDlzAIF~Me5S@Zt=6x}_DvZPXxR`r99;W3q6L(z6 zhp|U!@Aae;EPO$amY8bq=i?0mtf~0=qkS;iQ|8wh{*6uqoRY|+{mO)O_TB=~NoFOT zlpW>28CaM(gSO&3K8>AW-7t0C{)I;=Y0S2!(8&N&jZeacHpJx% z2Dtn1etgbjZ2L_3h3Rmgp8^E!Xk`-fVMgUjH}A6EI-P1}#hiuCq>?#3f-8D%1DM3& zlASCr8mkSuEr$4PteDN>HxbNLcF&j$%=p;o?&*>0*>pP$O%5DOht*J57AIf*L-1+J{$_v6+=Y31I^&F25LuQ=duhYdn{)U}B!^Jk)sO^d1bj@D=!ur&jS*BdQ|?MQG@5qv^-4=LTj(smfn+UM`1>n+ReaD^S| z8ea-~HpXkg5IY#24||+Rbth5I9f79pa;fC2GvYhP$E&k*lXNElB$A)Oh#9WdSZdcp zA^gt3@Vu2tn_@D<>LDmb__d_Fq%$flc!@`89gUEQ4Ota+1oEzSvavF`zUSUx8@ZMI zZusK5Gm4o6sAF)yLu`P-)2PjZ-?YQ7 z6MJ$aW@;+Olqt0Y!O{v9l3=@5xi$J+Kxt9RL>d8VQ%)G)>&90B@oBzl!3*1tr)e*& z+>uq+GF6Q9n}e`43X}~6#<|1(WD?Q>?!HSJvjCABdk@b-L45zO3NR#0XdKT;bYQ04 z!95GTJu9_3ooB{5)|FO_jk$w&mUdvQ_Np_c!n$cnnL z?2u{e33tX;W_I3lj3zNU$>)g^J=8-pLdy-hxY!Vtp54IGCP;j&4gQ#!&0aXME8yOn`m&+BxiMMT*sj46u!j2 zV#z8%OLkNNLv&_mx}kb_{`&;ln|*-23c1N4D)?5DC6;C3Twsy$G1Phbm)HoPM=lak!_vVw*dAbWflpiu%7xHra}#d6y#H3;2oN z$T-6w)Takn(%TCQaSaezg59gT7ZxI!qk98e{AxMLtGVIgkHyo?L3Y%C8!r zi!n}X5V1^Fz5DCeIBDq4>(YJfph&0I{KEnR#FLQY+#Ed&$xiwM+#E+_Q>S9Pu2@}`W|aUI+gZhWc%Sv7uV+`F8tLc?1z zod<*#Q_<~VwplS%QD_}FT5p`>cPr?P#8k~rkB#i2h9#ols$PkvqPX$b-(S*9XC?`X zFteC{cpteG7)7DcC7ZMWI3KiR>e#_;g{Lzm1!4Y$!w#Pwq(#7JA6VuYs2T#6xK2wc zqV&TW*>aalRO~izVhaO`=Uz+Q6=!@R-I_NXmjG2~o6q$O5GEFQofkehJHp&ixsShK z4=U{ga-z`05i)bMS+M9Figc?j+u6oWM2cZAv84o85|PPe!}8&hNMa52sw zx5f8Til#~#FPM5sQ#sy)wNGx{=C^1p@#}NVwcC9>Cpj;d$$VH2K+7NQ95>sJhClv= z2Ef=FcZ6hAQV@O}OAl5HSM2Qvn${%}ep#y;H*j&OYlW{k3AtBucHRW%bO1=&K5wKD z;x?|VCwUN^93~a{0pMo;3VD6hkj6w6tX+fDBKE1S7X?JuIDjCh?N<+ZxS<8o%#>9&RUI zFacZgtml1vwCio7OEJ{jFR?aZ$=L#oN7oqBW%f~#7oJgBcE(YNT@pyqBY>8_^wMZ7 zhA6wh4HCzPQt6R^(7Gz841%V&Wm9|F*!5IM9)}(Uw4_EM%An9=VA?LrIvyVlsIv>~ zu|eF`YBc$EVzAKhMQ%IsDbCsXTihN4Xcc!&4Bu-Bg*JP$6+PBG!bK_5DSA+bn@Y=O z8`~d;XXuoylw-Z9OOY=={N*lfma;V?8npy)lN2}i@yi}C5vv+c8wV3lCj$G`DSdWk$x+}CD3S9%V{ z`V%^t1RNIK5BCZ%dLb6SD38?+2VchA_vpERD;nTTI8mB7*=QYH*^iz*u=g_8=G6?~-ss_eQ6I|eZ+%VHEFV0twGwVY&3 zSiDMgz7#ca*S7PAvA6abvwU%sFO>@$miuJ4VLcmZpwMP-xqmH27t?d1n8GBBxzwqV z*&XycJEKBiAgVf>6|fDkueXnlnLlIHB0+(!_C4POkmO9+7B2!tB^aG#qBmpcFC6oi$iH_K*ni>Yv2TQqjFd0j zU-53&m_IJZ6O`II(i3Jj$hGvn1z+=ZZZQU73Cd;0AKEl;O?WF{^m^vBWaR$T`TY&2 zpK)4ABK&QJdbd7DDZ>4&tMvAm^h|!x?w$?ejpH_f`hySc&A;3f?$+bp1`ru0T*Z@xi|Vc-MzZc_us-Q$M@@Rda6f1`2rk#Aubm9!}GTT>a zyf3?InII_`n539uLP5ND)4ZJN{Xo>#C3D6uYyuPplMLfsu-=9PnRZ)V8?E@>{SV*? zFDmwJW_TL@KL1N!#oQT~{v`S!kaT1tURjXpEUhYoNgpyKISG`CUlAe+j%)#%K8(>x z2Vc2(ZKmUlJ_1nH!X^=BkuLDt241l-EguDBQuaCCE1YseI5IIoAH(3J{YB#EFxXR< zL_xTx0Im#I7(Q;nVmZpFW4m$w8X2E$_t6GN(e|Zpp8(j_LY64g6B|TeQ~8!8=>H_1 zqjN3dMEH==-0vP=^j_($t=8#N7^*XDQp@%0)vH9VK%{}`(-`bMf^olF(XdF};0`-> zYdd@jk7`jlkysq&-G~(Q{-r&v>);W?cF_V6;uXo1aYrQ&3b+zp|c+tsJhN{end; z*tiU^WmV@q8Q;ffKeQEajySzJ^NRr1r5q8ZKyFTR6|SzMF9FFPP0y^HqAYgnygL4} zC8aROjQluiLhv`d;FrkHSMVU+>?18JVa`xyuqUoK{8bF{<<-m*xvys!BSfKJGZ?Dj zHsk*S$y@FHE$RH`%%9NH zzc#6p!I!jh{Tz-w{mf1-mc)!tT&_0drCvV=khZ8d)0DX79os(TE_VHeeRfpY%rGAm z<&d)|^h) z_=I$HuUH7Y{|F#$HU%b3$O9&!hc_;NN~bhzUu>ZEXAIKLyVy$qM0Vb--=g@%tLPEx zgutEt0z4JjNis7`MUDr@?}Wjtm;Y*~P;l2aC|*;u-sBg8RL#po&8)(U&Zq6)Cb$+k zM${(zvh%;;F-i?(yk5-ND>vq7_yp!~cv;8i-wo(SVYc(45!}OToZRCqhboKHF9BcHy>RED9T)j2Nssx(^PgHi@Dw5s+OLZ2_%~t1ap{A z3>fPVUkzBA6ZWQ?7|T!Q3XtgLaA=a`4vUf?K*Gv}6twJVNLPh)<>GU%$ zkzdnFr`;KtO0s|X)}eOF+76%KCmj|rI8`_S->aP4=6nCHX$Kdy+KeCVpDJoL%A}iB zDm&R6mMA_5c9@-N;c4Z(oLMnn5ZHIXlmxD25o6vtCner9vY(FFDS!1WT3Y9ujd1_$ z;lNGqpB0bL1KD-)s@UDY{@x^6rt0Exfja> zQ7An{{S1;}ydE%hz)~8MO1iSx9U*8(S~M*vnfB2rDn)o#`i>7+61u*fc7dfEDG$av zr+@&cDa;kwqF zF)$L*+nHI>z?@D|_=e=DVPn+xYgF9pNuAob37(;uHOKwVwTzBx@}598<9wxIgQEeM z*wl+C)Qkv)wx} zE7|Kzs`Irz-`#LCfM{PlBZ-(C|0{Jt#z(f#?w-DgZk}DOOwrw?o5DtybmLY;JJBtG zog8i`;YH?0eO`XB>dtnsN71U&u>jNIPbM^U=0zi!*QfjV=awms$Z4?9Q6EIbT*S5o z!;)-=c*sGnVy;?f9ppQmiQ65y7lOsAFU-t?k6Lh(K;qBg_ z7EC7qNnKl%k>n7*Z>mD%Udo57tms7G>*7#mead&pS+A1-qc>WzH(`T@`JiU=dbAZl z+5s&${ROopF1uG+_8bNKh_?c&&Iw7GGmz)EQ`{S$UWgABy0?j(oYEl|+4U}LoT!yB6AR<=O*kMf85A4_kM0S*0}yq&R@8EUbJ{)a zSLqGrdv$*QP?OG1S2!cQU7IEb;;Aj{oPyGfhCef^;XlcrjyT zoR;hcxPB|&mvQG5N!-4$XpZeO(ufNu`QRMa&*?6JO5ED3JKm(b;?GZTuBAi?M#ZH1 z9__EDrt^KIfjiK`m^4KzwCT zAr*ZtK8%vkqlSz)e%}+etHE<%bp85TXteVu_szQp72~|3V#Q? z3#XuFU6_47K#Jv^jJE*A7>eqgyG6k>DybjjcVjl_0-z-UH?;U_lP_;aZiy!FosT*e zJKp~(xCWl^3ip+IJH88J)(b_bj93Py-tfjz^_KNX;Omab;iW;=vb)U~H;>GA$3nVH z)dL+qu@TAV6oz|EpsTW23m9}hX9K0ehhy)7FBi9ZXiq0UeYj_u6i}w|4BcBRvl@~V zWPZkBxE{ozM>7B^W&?AHvB*4PwCNY;SH!jJtv=qgIp12gKX7W8X5*zg#dA!FZIJUi zCYds47cMr1()g2MxoP({0Uzz?4w(x9mPq=TC&)9dKOPmyo#Yf;s#4#p;2pv}z}MYX z8Q<5c5$dd17Aeh9?gd)0r*i7QCf0fx_WBR^&Xp;rc+4&UUzM`m*4KTu+Zb%H1C5UMHL{5dNaJ-hMc;0^;LnUa|>eh{BlaACUxxS zz8J5;ISVge1AT!4j*Z7>J-Q; zMEDiQ)G`Yb)0~seKy7emCZUhTnW0MnbVUqQ+P;LoIwmnrl!r0-l}$hp;I>kvXKvg#3GzF>H=iLII}c+ zz@5+ymT3OFT){;^)QOtRhK9v2cW8N{K26mFsPbmC8hNyI9}ybyNHh5WtNK~A;0qR<0?=FM9P3IyD} zMwQnRTe;o+>TdyE2TGD7%GdX0L>*wh}pl?SIVndQndf~BZ=kok|@L+*lmNQxz9J#3)Ef;iDbG2&F`cI`+t zLr^!H()E$%c^Hs&%^{OswY0btNZcJ57UN` z0l6932zv-p!lj#&_zmmq-*NRQAZlZgX(+^;_@BPDkfU(rX^2zG zPN%Vr$mW$FZ$Q;rWvaPY?bu{gcCq&1a|Sz%0|90{zzQH-4DVjH+dI^G+Ke`% zrvUeJvD=@SF(~wP9d?_dj2@^RTN!XHF=~!%(o=z_f_y1F2Cd`ubW&({$JL((5UqGh z9S0>Fg_HA72acAA6G}N7>(5@VI~)BB4E5q5nMzN%WC_gCYI~IBR76{h=IF zVb_ZtTaG8510l0vio*zG50-zy`IAf~wGqWSpD9yhB z!;{=+#xh5%=9{;o9y+JaDmy1H+AWx%)XEO8~J zB-I2xwA+4d2Y)MDp?@hJtW=YnUkUSxb`qY1q)X^!80}B9XIzGuU}Qj>^(D?dF1O&b zzT7<7c}5un==4JnJ(m+OqA&?gvZ(!!&Y5Q{L6IV}NjfuY_Q|CkUYRUU zhS7tcRj@9><&yW6(yM@|Y)g5_3GK@-p^2^EE`BG?s{x@xPFeaPQtT@koThpW01^?F z@Np9$Xqhrg*Q3{3up^jVjXCre;N|!zGMV+>N=-7EuLFh;8YhP{erf1wmZ`N`qcxM* znlVwSO_{yk;Kv4id;THJ9?b0FrUk^N%xl(;JGaBU&$dZbb1B*zfSfqvrJ-fN-a-GJ zb6njoA>?@@(6oB_ZzRL@A-)NyS~4Q7z5_Uk+-}B~v{=()Gh@>iGSEA- zK$-MPyg|~?vb^u~MsaiA1w_vxnW~0eWf$+On=APJq7Bre{EI2x4I~}*pOXsfmC?C2 z5`PbHHAe6*S{gEQ%`93;E$Dsms@=fPGVny7531Aq@g@KE zJkj(;23EcteiGl!i^_Gr6UdM>Ee>4Pz~(nw@H+w8lNE8PK~ zVgC?D>6kvlXif@kG@vZ~%o)zkbBNEq*&ha+uEuSk%s95d6*~R|)kor4lv0vZ)y)Uy zonO8s?xO%Imen)t5Lnf4)s(spk`)c}hPxv9V?fk-n4>&Xs4NP79N+X2M8-?TcJe>( zcS{p^!R!76U=r(8F@dvS)^hrEIIhYwg9PpkOGqw93 zCzCn`34SgM!-z;IlB&p3`oX6#T%Hk>(S={;YA{##IqAWqE@dn-*E9W^(EjcZgv%68~G4y&^t9Z=)vDtLY_whJoEyXqj1LO5xk|{=1?mTHeKJ^1&>4b4kk|NT% zkjuwE4se+%Zcqiy986EN4@}iogBJT?LTV6Qp=~z>u?TxpeevaX)RckcQs;mR3fSZU0I1{mo_p~j8M>(~+$hS{6>6e!1Lzz;aITE!JA-i_m zgyolNeC;sb=S9CtaW>F~`_DARd06N(r*JUke*mF`FQb#8n4oa@WuPtSrL({jqK@d- zz|d+)rW1I}f%v>5!?+m7AF8C^q&TwR0Vf!ULgo>@S1S8Bg%6C$`Yn)?I5^`nI;T&& zW{8E&xvbv-Ch^V6UGQN4Y;;Gz2Y~NDka1zlgBxw{YnyEEp%#~#|A29c3q6x^x}!fl zcvH2Fj%?;+QEX=$J>vgWQ3u0?q0C|Y>u8VAjs`~i6F?QC^A!^BXwt3k|~{e*tJxWLr!ZIG!>~0GoHd>Yck(`OsyY z?=W||*zO=}{_Hnr@WsdohTC1}ugUs|gBJM1OF^O%R7m|dKxrd*bUG7J(e!tGf2(uJ zGHG14EWQ-zvJ_@ZocOv@#6JL{Z-OXS0{Vo%x+&nFz|qR&J}L3>HnaYX$?xE4}9Ub=k3r|(tnF)~bQ2rO~GcE=&jmq?I0QfSoDB-YkWln*)xaof}SZ`QK zK0-gN}0-RY8ENxhoZ2@knC&q6mrWfme~VV|ZQ8NG&hQNE1ppjQQoHr!j%`TE^#af>;3;_*qFtC?|54l?1XQ?76x?Va&HO47*^ z>+kS}jMkg}#x}Y-u+@8+OBl?zS4ip59aXyq0DRaY(=lO-zI}uj3HMSr=unK%Nk}m{ zVI{K`uic|-Vsv8bj!W0k>5-^2i4L=4qmv@r({X{{pn-$op2TnFjWPI~-6wwa)PBBv z81FHnYXMn%pBaS(SHq<~;jXwS+jy}H)a(w}30tGX0i_j;X_C~%Nq;PTx zgHZ!3wbj-_d$|E8eb>n3&hgz7qj1#SQDVQI)#xR^Hw30u5u+)qI2B>nKO~ez&&`Az zKiCiPeWy19w%(3RDDJR>hcVn?HLi$x_wtPapETf~oKo*3*p&sq?0kH_zK+cCzs!L{0)L`5jL511h`ddo}e& zItF0c+Zbx>c>2RPy|cDhuk(f05~ zO}?FhFZ`^o^ymajp{`}gG&jN0%qDaqKr|y~(w|0URLp*xx?Gws^d6{W+sNpS-P>uaom;`4Z}BWpWLTFs#_cV1D-887k<0|#mc^rP z6RU&cCP^HaG0BRPft5IL85hTbng&)2hmbwKJmwUO6tmL?eJyC>igNCVPLRvy6}MeQ zbZbDWcq_9$u?Io5#{LG~#td^F`YB~Anrk?s+uBJ)KB@GOgdK@^#jc0pk)2cf&opa7 zw*!dEJ&01<1kWOGCm9~9084YP1k9TNlYT>5>7KZ*^-PKM}! z6F9*oo#m@1&cJw80?O=UG@c`qDc^rE%fCPi(3uvbAfzX5ycD*ea~6i{g^+m8ETfLe ztTX4#S+%vwXOp+32$}6K^A2TW=?=h29DZ5Rz)1`hzr~$zAghj#?3}>+B+kxaWOA=| zXT3)i+`b9tjcZTPF4Y|YuKhrvZo{QoBEHZmU8zyOPqGf)`m>X|!A*)4cZWl7u-vCR zr^IDK)iCXivx&ZwlI~)m3mldS3}ZD1-h{Sp>W<5g?omGL}q)%bQx zL2MB--3FFzm}Qb8SkhxZ3P4>2)1_%Fin|qul?g6D8pDucNl-R6ETUfyi3&zcmXyZr z93q1#yEXd zz{vX$SqOB1h4bGy!^jC}*E~02v0^@ybVUHOd*cL{-01V7A_g-X*XXfE(H9QbQoY+C_lT`ah#NH>Ih3{_UQC)Viv~ z`QZ6lC1Yzy)=< zTBa(nwdX4d;2`B2Qp_6PXe>SmC4M0hPBSRYajsI=q z<|twh5w(E9EJ61#nKh8^_-tgSZff5RpMkB$~Jx6@qnHNW)1(o zMU?rGOtT%tGxqP^Eq6u9)$HntFBhIC67D*?wwcZ@WA;r^k=j7glAZH&g3uP+RYXf2 zVCdG6T)i-0u!3Qa!z!*lg_m!Q%~IFm6?jf$DVZJG*7&7>rhynbjOXZNipWkc3W7>b zV*VGKLOnc0on4iL)h3vSBXf?ks1J}N=)J{I7UEkZXkZ@hJf)07=-lwI_`?fu1@pNd z==zvthCPCbD>$8K*`ou%@V72!s`*YPJX46u@aKAFW_M4~K{L%_&zb~7VVym9NI2|8 zM-^Mw0GF(GW@?eZrgwJG{VY`xdx?_vbolbNI?IOU4_~gkKQOdwIGW#e@mV)}r#(FY z*ggW0RCbXxITz+C$^KGmCegmYe%+F&t2yPo#yW0;Jeub+b<@KG@f7V&4b1}-c#R%} z@t)5z;TCkEbKQE?v#MtnZ=Y#$Q88Q*^I)K9#h43)f?UNZ2KH_zXQCtnJp^dVFV4gz zR#f3$uvxI)C!7oXl0<_K1)$~{$+{Nz*CZV$ObQq2M_R!-q=#(^0BdH3vsy*YGJ55} z!_x&Sksr^ui6y2>f#LZx6MHznyk2>r@^UFOXCq!Uj9_ zq{2HNPdpl9bq@Bz;fiJG)vR!vW;i{&+%)$OaI34ixz&46k1>?S&hOCZ4eC%rH&ku1 zD&esJ)zMp~$0Q1g3hrkbq1uqbT_W%}z-!0l#QX~JI-6hu*N)nT(8pt}ZwM7W3wEf? zS;U)imJN?Q0SJi=%BZ}UM^s2dPXvUQpL0^u6|+ZtC2Sw*D4P~|5)hLtVTS*q8N5Ty z%E7Tg#hojEGGLN(<+CY;@!W04?N+x0AE8X;B(s6jp7f)&hIhM8kA#&u%RMJq2b>*fNKOhPE^GmJ6=xg2nL)3t9j zcp;Eg&$Yx|iPZZ-jdYZHnST*Lw9J>v3q()>zCRY7dCZhH^4?&QGUylIURjEy$s-q{QZ9cKaF0V1uu7tl1)cf z*(>by<3x?*&4c+4X{V^h#J3~UD=|E=+7cQB1ivXsAS&fO+xPpbEMTTfA!3=0-5j51 zdo|D#&dKZtB$)pdq>dFK@=<)!Ayy6E!+cG;lsiimdB)JW3_H9uIsavHkK7x*TH|i_ z*Wv+57h+~@vm5AWEiq4>@dtE1#JEt1h(o9LrmQP<&I6gnyX? zzDvDuw@=)^|2DvAPf|eiTzm|vZj!T+%G&|rg9PzeJPm|baDXH06}~598e!d(y%wBB z#?GwD&2IdjT>cBaBPFQh{t#Z^f|e40Tb;*t#|z&HV7=rw_k3eW#WkOm^Y}mKHM#Oz z<7Oy&mnA03zGZ4$AvdY+n_xS>+Ttsr_}FQmgYD&IdNG+9NcXsFl@d}Km!vdLw^j*jXgkwpps(rQlgTU3D2~t@OL|HSyI>IU}RuJ?d z3{*wAOl>0gpu9KEYcQsR?ca8DwWm8GMIQ#7-i$4NmR6*EC6v4NY*YM7v$jef!MI{K zS4MO!C5zOI72SE$V@}uQ@?IacGmMpc#xo2H4{0`et0~_#%Yu*O9(@c*s`EBe=(7~Y zPODj|*guGif91l$i^+V=1rpI zla_>n!<)$vgf-IZgT>*>e|;Z)%C1lWN|b7m6Ndy0=B828vOu2(Xp(c0%tHVT^yQl$ z=rfkQNYXRR9vOJsGQkVaF9`BY@X;&cKMT0TdCW+)TYlD!n~f9<2h!*804+@?cxei% zDZIO2w$|H+iYUJ{@beg|l$6xUtQ>~i$jmsd=;-(83mBtr`_Zgu?YL@`9oxQl*M#kf zpf6(hAL1;N>`@6P^LZFE(I`DcU$R8R3|-1UxswiQE#S*Q)ET*J0lqR^4}iUE>~Ikxrl- zI+rIxcvQ?4*;MM+Ep$OwWLkRc^27??X?yS4o<`pQR&v`d_=tBO-1)Dx!l`R?Q?e6y^k@aoB>*(y96gyI8!>+N9l-hTI zn<%x6O$pjIwFdNEpeR$BQHud#6V8r}SbKc=7kv-l+S$nz$H4F26>U(v!@*u_xhf~w zNBN^!{=}SSr|$z&g^#&hS%}eH{Ok^fyF-CLuuFFsZv&dW(71Bh-i-2!HpSr>6XVkD zzOFw$F*mb=erPcZQgVJ~r=#gY6J=ftjR+d@=$dBuq3$@^kCNGEg3^qZqaS0SYVD8~ zr6PYzLY;nsL0etMb1FX*epr+R*yKeYzTiSXwPY0*Eff7%(JRd!hg`_d49)5gNyhhs zMhIYB_CcdkNN=-j+c$7lTby2P($4{^Yv@O(%OTc*eu3}%6hJ0vipLMD;IFn>3Or}h zFVm-&X2Ojuh4eF@)zpbF`W3)lMvai+V;AJJw9{nXZocYk+7g zoSA7Pl^zI=pNns#yZ<);(?!voh_f^@RXW%2if04C1hG(x}4N0;cgmb}O-mG~q$ zd0w27bSX2HJ$}-o-vKDey=JHrmNNAO8^BEzZj@LW^c(F1tMq$-YUe`o!Ja6|jUf=Q zugk5>ojW%i#2;bh1ah_f4!*VnF|7S1WcjGcpxyRBGi?SM$%n z)Jc-^T=GVqnCkBR3y?JrXKbF`*rCB^&}n}Kr1pz9NY4&?$t{?B952CTzV6f(P1|Nj z&;AY1QuZ|yUqXMGRrcL9$)5ckFj`|~l2CRPkmoT>jrIxLj^3f>LhB&?!%n+k9B!E^ z-bf+XK=hv&>0W&@IC-zQmx24rx*Cvcc6VR?3n2P*P^p9t-AMkUJ?Z}M?1UsE8>lNe z6;k2P>3>tQGWHTX6cfc8H4@r!qT0cK0H-%fnh~>F!>S+Xk7UyiVa-_JQxW_k){u+> zGd_0{bNc!!z|)?yxVK@k%C^#U5?mD!>uC?VFk?wvS3++)#yNab#|4@r}1dEn&#C@m! zl~`@_-qULWM~h5pYEaxvEBm2uBbORH48U3gmKL|Qk73zWvY)#5)+fVv^h_P}Cf4{pQ+$>lfRN zGk#ypxu(C-HfW(wEL;zX(+1|u$uxg#y65ORc!1((N!bLEcUz+DC|wsLedF0FUaJSW z4wY+r$LMwzC=R%}YlyCgp^5)g>XP#s(UBP9V;K>a@U${5BBzJ_Z0P#-;jufC*&(~n zE?1D;EfFc;qX4IsTqbC=aBdxkXP)>=xOj>Svaa{?26#f!%8-eQB6c4V?#}F(n;qS~ zXOeCR+#~^!;jKVC)`RIo`lQy^k%?6U?3-|no(tW4bd+v{2dKW7Qis+pbkqk+H?|AQ z|Fuf(vb|#1Hr{r3_X59NxW_jX-ULuuuZd&q`JxAnZBL=aXH*u54`!MIzzQ7=7_GKv zJl_WxFD(Dpqcw2M=%#p7ax5v+^Ml7b5UcC zHhZnbRoa5_iMA9S7@i-jiYhUWyAw$+hsNAZ#{sgRx>cE#4xpv=I%q>qBDuQ)j1x?DMmAEF;icEg6MiDAPplm?&gGgXdzzrr^GWDDzf$ zg6??9_*jv4@?Fy|SqW+J-P3%;s7EIQFwsH77a)_+aX#-Ub^+qOyk{yxu{v9=?c?xv zrB$NJ5C>1XuVh2vTjPn!wJGi9ajW8}x9coEr#TdT8-Qtt^SYjV;cB`qzU5yhHtPQ# zSjBE`D7m`0IlR0yd-~vZK-J#!M2Z~*brVVcB=)P|89M)$@qV3&)ED$eS3aH!6m21M zJQ$eUxs>V%rU`4>^OxXU$L#^ArB@hGmYqX2TSrWk39k3$FwWdqdm5k;H7X&J$51IY z%L!2EI8T7%N~Z%QQRb424>T2&Ih|o2&;RxAj3gh!qa7a_-`zA#`Anwq+O5ZaCV*5a zAY%$P=L(+3UASifF7X0|wlE=2WwOYuf;cydR}9iNJIPqcGd_lug2W++yaBocfVRfw zdTYw@Zndn^cXvua<)3X=D5gS~#?QjKd*$zFVq*tGc}GAcwZ)9|**Q5kHkn$%*GZ)B zPI!zCA~Ne1D@WVz#V--DKR8`ZcLtDm?}WF*CYFUsy&AWq-UWlTo1BqeJJV2oF)|Wr zFEB{B1D5gVt^m}EOBgF`L_96dDpY;!GIIte6=qDcEZxn_E9Qrct70iD?O9@q3U8dg zdrDt5wR0p8!@3e||2pDXK>P7N!y zQDcjpC7laEZLfBv5@c6wGqAWIV15~$icZ#X(s6tGkS%2oiDZICG0q3`!li*D99hu2 zhPx*5(|}8@d_tJU%-~{5B-1Pr3?e4TZ4I19SZFZzzR=^x4Gx^O9&hkt_TdG4G!FFn zBD&;wi!{df@xl$ZNucvAiLnC8R442#OW8HM;yY60jP{3_E>~^l&U>fdb^=cu>`cYZ zQi@gNe|aYfdiQ*QX`U0U9aK;-jP|lUs1ClwhAzP9#6D*fH|X#oFW>Xmovt;5oMN zuOyo0w++w?#wJ`*nw18L8)-;hLtD?81-9l_$zv7;-3LpoC^&V&@A1HkJmvt9_fo>d znA6;SsQw0s+B~kKxG+1j8~c?pS&3e6$z8_SUZg!3P;A}Jgfy}5m)^`I;UvMDrk-C$ z{N27sX-f{hX2PwkF2cJAc)D^bvSVh$>6z?{1JGyd*W2dW?rEnQE6@xBL(RoyOu83_ zDMKtNLytfF-E%;*6xhhO^zeQ!Qx@sbJOH(FmEx|IoCUr=Y}kpC`9W*B5uGTh z15xLC&hg6~n8#}VSPL6UMerA12$|JNJF^5oSfl(26pb%&*vfUZ@sv{4sV z-vwDjEe!Iv*yq}XL!QAfl}Vj}spt}nRM((niovC8Dh6a9U^EwQM0JCfW2z`0Ln=Gs$x!^+8FH}s!S9IRS<&0 zq$Lj`_iP|a{e6q#UI`WVx98P8Hu z0Nxl{{vM?V16dWnH=F2iq|!rD+BOh}I#;l?I6M>>UTaHm6E-1tq^UACJ-vIH9)_Wb z6DxLdIFGq2bZlCl9u6qYWrE`ck}X!GX0t6UbZI;rF`W@YF!(Ns$bnjeGi|O}n=S*u z6?^r;flQqy3ZYcfi>gzo#&1lBF5?k$~30K(5~@T0vw| z`Gu35l5&?^nsn+If8tWAk1~rHTdIsp9`A|U(ppm zo(<0^ZSk{qL?-7Dwm93%fRq6O zq^AHY)5sw7gvAcA`iR`tZ!Y(EDln2&&g^+C3>=hJo2&D24*zMu@w)c7)JlaZ`A!OY zx*^}mOsO9nOO4smINW4@IS!UnitqSFQqkOSu6%Z*pkS`OQ^b%^!dQn zVNS;UW$BB(sTZUq*8Ca;!HwCxy;L=c63)DowUoiH-@SA$(kb{>HUs=ZJXp12WW>vo zpUGiZ7Jrc?zTop7lhW^&!SKV2%^=4QQl$@bg;9zsCG-+}f5d%%gHW(W{K^KLo-?P5 zunZ&AiH;k+G@11Ap4h;U8LdPw!$8H1yZpdFxtk@6^G5k@Ru3y2AL>g=Uyf&J%`X|& zK%Ftlm09$sRE(~Cg(a=92`72-jG~aFHM2q;7H!b0OwUbD?wmZ2UWxHZFI}m&04r`Z zJ*kt?tI|0MWntlf$^V>NWL^}t(p#igV{q{$t(i(}EFIWmq=?+_6W){bY+u+8T7k-2{0{E)I+tbNOToH7X=M-_GeZCa0V#4Yz zawq9K0HyOf8))|px)14{K=fQ85}lGo?=p{e{4J6Yz9<%e-W`8a#6Em8q%kL&`}rL( z)4Sx&itn-WE9m7+#=%KbK0JOeP>MP*df}+tQ{$CXhzo^}R5CEPVG8x0oTkEt- z=|jNQrn=Pm%Xm*dRsLbX=v0@)dSQ-%Q1(&jBN*dPn`abDq!b)SAuwxqa3e#HK8n%B zY)h%*SMaNQOEt20n19R?UfA(WY~yH05?k zg8GC7kJ&s^ABmRAmwTgA?^bhu(k@txB+FF{cMw8wNXE;K+e}d8YYe!NtVf>$Nb$Ko%-Y0L z%xEZ>z#%2G=oX6(eG!1#&~HsQDWn)w)`Y%<(dw3%jB6Op%(m3ZISLzqec8^bAcx0z zDvWoCrFR`Gy-tm9HTVh!6|+S-O~PKecWLbvez6PoRiJqFx`Ad!+_w$U*c5)CubH9o zPUM`M=;^kL%)4ETW6EmI_o6EjIN|)jc4E>iA=Ly%qpxFhl4=qJ&z08Hu$6U6)%fSc zm5Vj{1`vuSI>TGeL>Gz_JR7*pqv{%6`liL?|N4YnNfDAkHQHyvdeu}Azil5^;7@U1!uFtN<{k4JzJI3V{ohkXyA+IJ~+4`4L% zc_;clVAR{vGy1e_;%TfOjSlVydAevifM7jf-AbK-2 z{RnU>92fBm91;ZB_H|7+jU+bc$97@`9y=%H>Y#}siE$2NN~#s=jgIsaK+kWWsO*wq z8~Gm_i0l<+@TBOcfJ=^2&ZLxrKCgL~T70D~)t7J+EjQB6x0YM|wQzoXNAzd?;)|ap zt11R2tZJD_M{5C`=$~g7SK{ITRK|wv1i3?qzpzlT>dE8bE(zf zzT{sfGZTU$9Tr43_YKVvVKO|L!qJwSDpFcUaO!Nr8R!3kjo&LlLN^YjNmB;}Wko1^5H z?CAzJaMN~){|J~wX0L<=Gi5Pf-RjYwfTt~3MyY!a5GUCuP|zf0Tt9n&?$0Tjq%%B5 z)Lu(}!S{VzlkiE9Vm~JPT>DnYzow7Ol)YUlsr>be?$TsaG5i}KN7AFu5(^tYma8T# z`;`g%f5tKRI|gbo6wBeKB95DNpxv1?R!8n|DF48@MJ_h-`5Vq; z{S!C|t8GxmK@o^gW%X;T>^HEM^!@vVTmN~wqwZUryZ2uTmrMN%&sMhcq@hw9-GoX1 z##k@9nQ+u^qH9+CUwqvcVlwuA1GkHnpYyr?V}MkqRb(J+TTmP-aH`;aw)|dlUNz{} z9v#9KrJyTh3k~C>YJAb&6W^@Lg#uRrh~^}zY8nu!pl}N_f~c$70lIBPD$FI%wFF-+ zeU_BLGMsMto~~|372KSRTd8*qdED*xmOH*UoU2BCx(1N6>B+!2)8lPt=!5r{^Bf8o z-T#u=MJqZ(OUzgmx+c&P8QPlR<;X!8)VN0A4t^X4fFbc{MuvBek5^|$rs!JPXA2Vr z^;qWQxHp>}4xA*ElxRG#wp&|hBsv0v{GC0b@xphNRMEBZZ7+ix+&$9XH&_{P_t{dd zUn|itbRFRNRm*TenGo{zJH*YR9l9<6lG~7`(|xn+A0;$G$zsA7Z+!=pk2qA#{d#zq zzE44RDXduZj6%}HX#FDrlANxVT{04g*EVyJs50fR2fscBsT!aj5UB@y2l-KUfYuM0 z1$L|e8Gw_ERKO&D_MSf706>Y65^WurGr01&3Y~6mDn!v9Um-MKfyGnDZW$0*v4=oxJ8d^2PnurqykBTSucoM2@#9*&6^F%I7>|ESQ7 z69@J!pmY=9>QsHk35+DtZv#8b<^(+(_@jZ5>_Mic5V2k%D+BJ{W8Y`3niToCc&|>a zPM>ayhv;xb66%I2OU`P!{3#uS@p%>vn*nX&HRjDQ!0VDs1mz5gE(e;+m#E1R3BQ>7 z<_19-a`C?cWBR9yQ|T$b1%@jYy)v~#_!ItA`>_^@|9gnf6W_qAAhUMTG)K3@S1)%d z^2`=m7IWb|5|=LFXPAuR0;Di!Y?e8>Ghhp_bx)AEm(eZ%R5mcs^)K1p+d74Y}%q&fFiOm58r|kp)>YR`4 zwclY~k89WGMcC;?4EKg+i{G2TBy3vskxV)XBNTUJCJ+|b*Q~DeIyz)yX3W=FtM!}yjimOwIyG}Evlww+NmNo;5l@ha&4{^G zoevz0OwZEEc6AD~xkox1yTy@W8g6$xYyBneycn$7Vjm|q+jI(^mAq;#lT9l1kLs-W z*`D4yOSFhcrk+N(!H~0^xMmWTPH`_Zc!u`k2Cu*44C8Hqq8ceLOjjy4hWt(tY8@=` zn(%~O<_p=7>~?sVvWl79Mf@=I3mF-7jk#1Y2yW7{&YmG8qCHS@pB=tKPZ60UqcvLFEJ6HVF^h7zG~p&)>Y+PetdC1F(SBJ$vo{2Et1;C5dLp*XP>Rx(kK9mTrVDu zriN#mq?l~y&6u4O|5ub(rq&xVdvI(fbuIxdWh_ZF4n)oG8*~#Vw?e@T@iiNKx|pBg z-XL=xVAXn+pz>S`QDMmuGgf)DBb~mep-r$LxS3ZPfl7mR0!uSquE-q)>NQ&M+_73i z+8ySX7A%XHPw4z)+QKG!i+zH@a2xNJZ{oec05~rtm&b|dX*HT${&f6mpFa@~zp2+- z#W1VUT3Dc6_-e7^marW2bcG02CB8$KI-OSV z#qYb#_%G()pw;aBGioO2L~RJ@(gE!xN>O(VKRYweqI>+tJ*C;~UFMyou-tc4bd%xi;S~?bdq$FtwU0 zomSbIOj=I}D~Y1L6eSl;nHZICpNfOj2Le^a=90%LN<+j8R-unXHwa2Q0uJOp$dbzc z6-yxk8~DZJi&x;Y#iB&a`GW@oER!@AS9A!X_Ygvr?jaT}CQX1mL7WB(@|x3=@arB5 zAgw5G>Df5~vc3l6xl6MjhG9NyoM8gz2!ucY_hdoS;NcXpnAcAn?Cu`IuTC_z5md}iD1?Ck9BJl#b2Tu3X-c_rC$ z(OaONWBEx7k&YolJCDPHAkjT%U&pc30y|k^r1p&{(K==7#TuU)x%sglG3cE{F2nDx24j zVP0H|x2de)iy%-I*x8O&m(2!RNH&@jVhjtgY`^Uq2+}(b*}UaV9H-Mt8u`w;n}e(S zVtg^p|E*{hDh)z*)jQoQbH@555L?)osoa~Ya*kFaSzIp6dnsh55tovQM>RDYH@_6( zY@e4wN;1tYF+RmJ3QqXTi`tbL-`qrjYr7Vbmp87344I%Z$Cf9k@~cj0h4>15 zDQ&@$8Hx)Oy#MGKguE`C;KDz0Jm0+%A`9!ElH!C}o(vy*j#%-mqzy4L*>o=YRmCb9 zDpqx3xzao1;-V-2G={49SA((zf!oX}EosnPx5!)FA*|E#{%*Dr;a&r|g>>1>SVZFz zDuG&-&X?0#jo=OQI($2gXIHN2{7NTeQ>^P-J3QLs zUXQOA=8a4X-=(NZ)G03rs?l=-ElOJQp~N>pOxm|Hhd)+;w{zj8Vlqs;QSSXN7!0{u z*S!(Kq<3ekM58MLvvq^aB>tx9H{sjqGP7jcjoYGdj1vWO*Ok^ui9?bv4~HzMs&YBO z{t!0xoZxl6*_SKt&y^G|&M5I1HfBf)doMKITZ)A%kx{h}=QkYQ$}-gCRFWOi-FpjJ zmDCZCT3O#gw|wKUk9!-$r@mZ?V-Y%a7O2Uhula}6u7{|!Z)d}*qGys#;UkFd27Ec~ zk|j=BcXQ`%gplNbaoJ*#2Ppb5y+H_%5z`2Kj}iLScd55?NmQMeI0VtirJ+7Q*lV=L z>EM{_jC%(JrlFh?V@}<1E-Yrd8Z)osO%PeIV_7DWj5>*V=LHTRQ6z62$v>21lkbGs zbT+Ptf6KzC@Gj1~AVLg6Nd$}=F-}$^G(%;vujG8hyNk+X`CcUkrZLm@PeS;e(f8oH zm#JLjELt7ET{eO#hmdjv-pdkHFQ}~H;w>cQce%W;Sf~=$mMbZXJi7P$Zw1$XeQ~4?WJFQ4M;)VH07tx|WPE%Slyt{8n_r><$j^I)wU_%CWXNdUAe9xr9Sf{3 zqK~ob;Z0*4X27;Y+`IocB&XNVuP(~ZYuDLHhN!+++eR}zHEC{pEq994eIl=MNfX7s zD$6sj&~^Q5`sgB##g)8b_$0)nIkKs5E&=Z3)!vKg#E|7_ zxvt900v9Z9M&#F3pD7C5P4l;P23`2G_X+~*-ddT4e`E%wkbe*CQX1^lhVYcoeC4t@Dn!5NJkU~Tus(vp`Rja?%6qY2DOI;*C@*P_;H$WUBl}e# z(n(^YltrpEcP<|bpk&n)Z3W%WMO$6rHN@O02lq7~3a=uT__<3e#pJ^5yw8=qrC5TK ziY1UBAf2zF%Vrur=lSdSrsU0Kv6ootXl`h=-JoL>-@q4SW-OV*0Er`*Hpt<7W@FfW z)ARD{j%>V0$e`=9Q|?<3kQ|)L25szAqJLo^Y{N?_--d|7*w4n3d^z9b75P83aCYB; zw8EL%Y*RTZRn^ny=#eWrx72puE!FGjVncGHuuJB?hi{!623Uzv&Go1(PQU@CKG~*_ zjGpg9R5}or>x_kgR(E7`e^3-(=|G2|PyU9FLbBBlAupZdO3YZC;!~dnX;SV-5Rv+2 zUHd^QVqu=5o=x_Q+>eW*GHogrh%oB8(1rU6M5Hrsw#3UD)s?$uXKLZ@!oJ=M1_ws? z9>cA!HCv<4+)p9skBO(ax~d!H`bP-s3}h#~CAx#_jd92G&mcEF(p|Qx6<2x^D1w_F zgdw;4=a7?jw9J$B1)VK_>CpXxYv{IA7{5Zh;)1f3CfR3Mzct#kb+rZ6OaC;K1wwua ziAgBF#NF?1)QUIa{0c(TxI@W|#lsl0$!?`V`lJGSuA26He+~JmYkab_ub5F>3(R+7 z%T_kLc$}^L4ZdBH0jWgD)0yy$X{(WLCZHSa>4Hq!rgXn$5&IKV_PDONpkxgY2cItH zh~$P0rANV`By~4`X0z>n2TmF%9hHJcI}O>=;9atr5e-?7WamMj>zp2S`8`NUKgjlt za-i6=vuIIn1&Vl)`vU}}eLKtPu_puXS+b8sVe&shRvJGnpIFkY(qHjaac#3r zrSvP(#1~U4Z`ET8?r#tz{&ZIHQBdrW6?3}xwEqq%g-N|6?8;-fYy2rJZv7h<|A5?d z9h6!4*f~Vog8PEtD<_!#6N1v7(I-tRUzg}um`e*v(mslclLhDgUl5*7tR->$+{BRt zW!%5aIq_@or;=S(-?dAQD%1= z2uj25yW{Vp8k+K;?`=z!$zm(9B=i=~9G#wucbks#KhVF^`?+%Asrx^cM;#*Dyem2D zW*VAYTzWr9Ox@56x_1ftc7twL8te~V(kU`4&DNdncBSo5df|{<2)fd>-f6ESH`Cn? z-z&U6QeqbKy;q0OF%1up6XAEH__fUg3i>>>d-1a!yZKg|u8yGrAqnU4dWYVyt2Yw< zB%SYXUqDt4>bRWso^iIAML`#7%b)q@acQAI z?^RPu(INPf_93$6X>QCl`HjPDuFHF?QgePvaCd~rl8l^^I?DGyzp2YxqI??RPLLy0 zL5W|U|FW7;a)~4(xl5LM!?k92_LB3_jci;=QD_T{=ZM^N><-2E#QVvV9qucj zIvBAV?oxO$*Bt>->4+-v$R(x~X54sx9zCnp+(uT08vaN~O2@=HsVk`v@s-dx)@m$W zq8tV3>2!XANcSx$*OT@2j)aTK@GtIYd@o(>m;3f{IwFfES8bE8{4KVU=+z zR@oh2DsxGWH14UuHB;_{()!DsgQ%Yo0|=JEod|h_C%Q|5O2G`wPtQ~0Z5@wegc)Ik z{zVMRNsyMD`^sXpzHdo4SUKLBZ_)n9B2xd{UGc5NHk9n{2Yzm2j`(9)>N3off7<14 ztU}&WWHFyEW?b@MvRUNrkdv-hN_xTWcuirIaxw&_PScUez{~QZ$HvzVPmH^J6so19 znWb8?M_)JdJ#gWW=E~mDzMkwG<}pgVj0A zDhtM^v)v1FQ`>j4$W43DP_wh1iaO>=^^M#(d0 zukSvPo_L`>qFO9+Fk8D}mf@xQeexBMn_A?Op2mVHg3sHGv~NRUaK47HhIIH~!f29n zD@qU;P?(e^o?0R%}TBOFw^kw&b!u+`hKvEjR&9WzAZPS2Pao1+UJrG|l z4D)PaNWNX_*}=Q?>n`?B9>ntUBO}W@jKX4`7r(c$ex|jhKI0zTT^Z>vdFK}+n;M?} zk8Ta#u2TP3L!PAmXC^R;L64E&B!!kXs41vYr`=}PgRjdnCo>fCg=}S1SRO|o#jWuo z^qI4gfbnjuG&obH7ZOwBeh=xEQME7)rD-5!+1=XW*R#fsU(XMv{7st}HN%Z9*dxa^ zd3_L;jF9o7DtTGm-re-GZfmYL|12l<^pF6&u7Ij&5SiKQGp#AwN^7NOy4-p%C#?8N z>}6hCTxXxYLE2CMl6&!YLqVyEAc`oZw)b3rUYn9hAKK85j|TW)04fP9mKcm$84gFD z2T_H1OiBD13xnKZ9+v{-!|D_`#Pq)r;tK16^NP(IXK^F75W_^}I}ZSoy2K@s$$XQ9 zr^3SO#n*;^wnY{ogT6xZ5si}jT=D{^79rAn^x6%1!J*#_6ssZneIz{^fU@jCzh{PL z?XVZ$YHTM1J`Cxp3s}-O69)W()Z8&^ZKH`CUN^!bb6d|Ri`ITxB4=J=rujh4%66Sj zm7I?+r;GjSCE-r82H~DJN!}*oApLR_q6+;o3$4dFq0%4a`(@l11f@e2oNez5f zTY~1fN32T8*;RJ|q)5=P#4pZ|fgNX}Gr0@%U&)M7tevU`f(MW#nz9#g5!XfD3#f1; zvoc^X_`C0NdqwUcd6hOwgT-2iBO>|%WrKpOChZ>5(8yUj_fQDGHs2+T*~=dx;DCLt zO<|CZTbPw6B4COJam2u{701G-VwN7}%aKQw^o@Lz(7hd$WxJEIX7YPy?&10RC^40W zZKt3&op28QtOi->QafAS#Tw2l1q<#TkyoL_NKuGK&Q17u0p0GGb5~VZq7Gq&Xj_>V z%oCwV%(mS`-uk|Aw*|rqmgaEjHQwqa2Q*y+-$(*anMGk6DR~C8K9HB~*Yywek8S8% z>n8cjY8{vP-LVR}llpbs08*8_d2Zs{C+B;_(V}SlCMutPIP-R^FCLqvg^B&h9axxY zwl8zr=-*Gd_$Rla|D8H{VxNh9uIyZV=Ud^oE5dJh>NS3bXIxL2x+Q#e7yp;?y@S0J z`Q8^2DQDa|FY_1vFSiFNNXtBBswe#REC1QG;kTRj&42G~|Cbkr&yf8P^}NOtI^nbX zC%nrO&2Xmolqn&c?Eg~e*v^mT!)x=g>^S@xd5`y+tqQy^`_hVLANQZ#5I*}u@|O?t zyvxF8FZ93tG5m&o_eglD|Ll*JDITJP!d*`Y~^rafIWd#(RVY4>L(Qf89B!~w&o%bmSUA$;2ZCYsIp?@2#vC8hnm z|4ZRDli!X?emgAr?O$Fqk%5J`|n*F>hlqa6ue~^?b2V865;8*Q>LVraJ($m z(!>2`1+LAMBY>U-c5;S{r-b|K;Zb;hco9I??k>UQa2*n&dN_x{12<`p-n>XrjxD{b$m%?wx$L(@T+_b&anH zv3&a{TE92>-dRaqZ}Ojs6r8O&WlCnsjfs>+|C{LYbg!B8tgj}ma(n-m^4TWO6MKe$ zU-S#^;Qz8G)aQW-53#*iOGs#lzkM(%5l)cA7Q4mkBJF;iuNV34asIQ+>iaT$G|*q| zf0NPi8vmPo@0*FtVgH%fg4-v5iFi>Q9slv4Nli4o)>4D_Pc*we`E4YT+3}wV?;rlN zlY`c?iDn~7kHigGvCghbWNuBqcXZMYH~G&*&z?lH-}=u)mk%W}pX{Z`n0{CCy?6WH zq!-{8tEkyp|CyBNJ;`4l;d%1e@&0?F*^&OUH-wt_pf9_$-}Q-R$N0aL*2Ky?w$Tm# zFQtueJ68PcJpVo6JuQ*4uWwEH-iJJ0{t^rIDCGm5AZ7n>(ndEYzhN~UzxNscJ*m&z zCVd|3%=njxna1Bf=4Faz14%n9BwF9>KNBm3g=0=iQWJwo`5u+%f)j`Fd&5aytYe{N;WunWfxkg{;`LGYlz6zJxw^!kY;Z^jftJ?EZ({sC4aqJiW!pwQd zI+TK-ZQ4txxES`FCwDrsO|STedXEik@yAMIa8g^{JE=8COQ@9|8Ql?ZCkZK zS2Ao{)tH^6>S(T<>demEm40E`ioOe|`Sw}SagTx&9Fv7K0Yg2uX}=GB6wyneLz~{{6DVf6~q%W#2R(uj_HcWrz^rbyRH@}o5$aUuX>mKdk`(iX8?)dhU28+T57Qu6 zkk0}Vwr7R!+8!!2HlHP8#Xq2p2Q9=~GUY-?t%w4OL*wf}3 z6XCCba5e+&g;{zPXVJY9|)b-0J1wyikF?1~4w& zJmm~E-JE-^!kus9q`7vZ83RT5uLGZcsIZi0MQ^vgUeR}_Zo7IyUaa8W0GzjalkSa* zw6|v4NrAm7gKcxyDcJH1)iy!AIYVr9Z&8T7Ri3Q^dus-3xVI_T^2*Z?#Pu0si@QM~ zdiFv;+#;YGGtjJiy8`X0$(R-4@5qGDxSN#lz11o+0(&Q5^aFE2Hv(*T?^48Nk038r zaPJ1ruVeD-6=XqGI3`_}L?ZP)km|?flzXqze@~lZN`$`;!m;v$L8Z9_%h&fS$nGq- z9Nw8!z9TOcGP#2MKvtd$+y@nEPs?+G2>(zfe8GKqF9}}|;UCF_cihcNIFi#UT3MEg zyFU|jg!s{nxWj!+5tq9--64>VXOK(WClq9F4arLc_Q?!3?>?nqd$kVdh4|@=*mj>$ z#O0ahwje&6A)Nc%UPU-Td_F_$a$iu0JsmZ>MEDmWoP#bDrfSm7RbNtw-LU~(T@98i zz%K)MdvA8;S}Xi}j~(|F#oV10WEZ=W2^Q#A0i_?Zb>1|&uPNYadklB;RsClIy9KbU zN^uX(*A;Cy=Im}Xt~9}Y1GsEKj^LsDrsD0+T-T*KX>x#A0e%ZWZovgw{jb28M)&Qd zBk4qXVdB8QtyqzX736n-M6_|m@UZ)?Lg9c%h5hY1%MNETn(smU9U$I!kL|dwx9z^K zIJ;pGyR{lVW64sg9{|fUFwUfHt<#M`KUC2E>cZ{za}T9J4014ktgy@M zp)6H!KLL)bm(EhPTobEf_fv&jX7xtNg8dn=JTPXb=@=Ik^XH1W%z+Wa3h);IaB$EBb|dfgU3diYEH}2Kumdz>OBT_NwiE zt29}rea{37^mh^JZ3oPV`@MqhMq?W$2_Fmc4?ud~{0#R;McUI@`3w>MCkRK^jbWre zE5>fbA7ZRq`{(f!zjKgLg#Q=tIpT^)t^2Ej?~Zxs>Jvb!!2T9tcpTpSeQ(1cRbc-B z>|j4!g2mv3R`*Xu-Cz%vZq_~#F7SU5W5HYe#<_AIoclNZ<7MtYz+Zr*;gQ9OxoO;j zRqJU_jITTGtg()R?fS1$u!~>TSV8yKt)fK-#DunASs_<+`yYw-6*IDkTW4yN*<2gz zzo^gcLl!N+sKxy+71J$qF*+kO5hk!(k<1GY@`YVH-RRWDnw|bmbJpEjv2b9mD{GRz z9a(u~F!L zOJwQIlmU9v%l)6Cb}>p!CFg5#YI@sL#FmH^_Ch!pUF03YKkQ%2<4CPoyE%5(hLo2?5o?jXhAVDT%5Wl^|jaxgSG!fP_t zq^$h8Mzgk#yhT4q`^WnR-62YgF3uD;aXZL~HBl~ERJbEl;GX5HjK|QO6xQrnC6(_b z3Fgkgz?&KIS9H`i)Z6Q5QMy107>6nrj-hmIXuL!ji-#LOa^eJd7=T>0Yw5;?ahjKE z|D6Uzxxa=15TV$6@78MSM3T&bJ=<;3|!*Q&}+!2awT3*~35UGhU zfgK4LkEV5Wg1%GhrPKnqjtTnWi4Ro{Tn8i#x%tJNq)_GvX)m@TN{bWXT|qp- zmrBfF-yF=~Xnkk+hd#c5<8F#SU=_8}6qW--qq{?+yLpZ1JTk`1I=a!B{&TLidAc*T zj`Cpe!sqaoi*Z)&WTn-ZrB!oRqv;c&a+PCqM7euFxw~Y_^@*@SfA?G4oubq+%}JFy zTCyl`uIV!Jj<*XMLL(~E$^TqbufrGPnMCcUIgq>%3oGLE+f?_;p(wl&c-G_{=W z?xVO}g4mT_NFq_ND}ZIsd5}&wyTwh@&7C!H*YGNQr6QX?7q776&?prv_*KB;*5Ay* z=H5$PrsX^5XtUm?pxmiS3*1c8)ew|5ybL%$02M(LIt>aPnOBH>COQ#H*ALEzwZ!R4 z7qb&qj#MRCbT|V#@F)l>^J<3tCcl_DQz>9JNf!m!9fMe*-xu_wd<~R1%l_&Qcb3v% zz11AM<%oOPqQ==!1M$7Eq#A1Obmu6nIUSU&rbvz;?gs>W;xJLejmCm=baTzQ3S$no zvd)&5D8Tyz$YUH;+cUQabKAFzEA;^i+a*rGW4ydlQ>lV}Akgd^!U}D66pb09H@cm3 z4^munIxpC?oHXG*I2Kj$UMoT4ZMduMoXSLMWxp$ zu35!ZEt{7r;9h{aiUD3zpX_nl7G^1B*sWDuv%FQ@oKV5`0n3YvA)onM>zSN%>lD!p z25{DJG}}>@fYwJ)FCr|wirJt*<|-x)t3*kH=?8`fiS!&^+zqbj9dqX?oLQ5VJtqnk z@%qEQ+$NS*JR%=igdUk1vA~y5)&8232+!d zHm1F}^o>>zZbXqxV@fx&N)|Q6!$giC&If{r-I~Qtv&Z2XGV-5r!Skp>nT@uEB-9}x z_D3yLxMSe52Z2#n<yb)`$O0ekAfDR#&A>p{S%^4rTo>XizfYK!p7i0>y2`u~6VP@-}8=0X%(c0-9 z)8qziRcO;QsF*JksRG{y_#wVcImXk|UfWv00%_*o^sTFO>;sn=< z1r3pQ^0O#{ggf?lN&0?Xb4gAtGH;JgLa|&-R$hyQ?m26R? z4K;Y+ieJ`C7rWN!E_K&Ycrz?g*~}tRs0*Nmp+jq>+E{CAXKWq;-W`f*E?aQKE7~cn zyrMM0?Tm%wk?Jdh$LcNxG%bGVSd9XOxd>)%KToXTrHW^|@FhD>$_hR*qG*{&Gf!~h zAEi*Hi%Vg#Se1EEQmD&7;@(o580zmGUfWk2AD$Q)=^J&ARTS9r5!XZ?3$jYnAmdICUf zhI{MtZEP!2^I|kLcXiwo70@)p4VDp!MWI5z9Au6ie&nH6vp$HdU4J*tz!~-!n-mp(_C|#dx|3MS(!+ZFrEs= z@!lyAdy3szpLW1|0wLV@G)3M>-|6ZARvOn*`J&I$p%2$FPu}RNn`jmG48=ExDT(i?wmK!#gg$nuEAhUU*HC4Ucn5O4y{Ubz^?m3EU zx`GuewM43bp9?UrpZaI<&LXVRV13(kgMAqHJViHyyLA5|iHS8`Dpv5%2ma2!(*>U? zIIM^ny+EPOhOY3NqDaAB1#HE_gYBntS1bCm7al>d=yAl}CJY+n6L(&@Ta+H>-IOFdE*f@spu@ zsbZTBYw21bktyVtfy{d-^a^Hsinir_gc!LG<1IK|?&XSZ?xD~jNeGJFyh5_*a4mFT zr)nK#QTlg;F!jDdfz1g+Qq3YcFHdl<1dffTkLZn20+`P&d6nXsORkc5o(L1zs{s?I zVpf7|uTiAka4N9h7t2K(bwQSZUJDTCcLe)AI^CE;=2qP`*R)zQ?sW=kMtfR*UpYd{ z<%$BYhXNe!SxXO9I7~_G`?xnKvN=0ULcsJq-QN-EN~mDp2yD6mhbd$;1q!eg=-#B* zrj718Gl^KCUk5sZwd@96vOo_xy;%`W2VLdcMNvX|3n*N*VI~-AZlg(?Ow3yq%v|VH z%mX4&kZ%K$yAwYqU8ARfC^N+W;?2VKifo#NqCqT|EGpap6_N!4M>F&S;YOv%aux`s z1X1YiP$&svgn-mLlm>em#9(oPy9qe%*_jz52V`w?Yn|>vZo79XsyUv!n8%!4!M`h( zmL@IQ)gHtCK&|86t+=M~qL_Ld#)&Lpy(hAKG8d_{&QWHId#_@dZjNhiouOoy#Gg$> z3i5qGatCL3lS;^~Kgo8^yvdx4RE2B}`AN zq_WEdixwY(7M#k(sa}|PKdhkU`l&Q&j3f!=BcKFNnpU~=x@D98*Qb`!G(n5rn-$TV zA<_&$s=%U9fqxWm4ohWOX1sy-F-0{e{PL7FFHC432aR1u+-SgyPu_ zO)(6XlPAbe0?FQESd-RrbHDqPqMDv-8w9jR?y0wuRP0+kI}SXq^dFB2>_y2RaSkkiC-d%@>wRt_(Mg4>~@>cb*lq9A_}k)czOvGx`IONHFiP8H+{@K+J&Po?y?iwUU!5nKZ%u1~~3g;!$MB(b*;4L*K#gPl zvTA+*05379k`7tx}~zo1Ccsc0&2|5n^R?NlU7 zK>q=VCmcU)@IQzm_w923RWx&~7GpF@q(J`%C{O6Y0_GM6ZXeoX%;&S2(@sT)&dC(; ztw?ks2tx@P?$(NFPOcThm4YxNPH_7Im)r0cJAWHRGuyFb!(Z9>+X8jC@44z62G_9r zKgBeCUp<$Wij|V?m&1pB+n^xFN8J7jZ~CH@`?rZ);olB?c7}646AxgYUg!=`3Yc?1 zI%dnI3jX%Mrygp|&2@KB=sovPqfj9q2r}>Ug-8^folxlqDX=+$D}qo_q+kyQme)Gi z*IctOJwqu{w6S`KLYlKtTFr?tf!z@>w#wpA@RlDPF*xIN-^e&)d?$tOr_r!y+vg?H zMVC867cRKy;v2;ss_5p#Sn1h#dBQs^^8Be=G=)zDyNlwPvHRj|mk2kn* zHPaCacBWOeWt&?hNFYZ7!oxM^b^A0;3WZQgfjdeO%?*MsYmcygWyzw#(NIC{I8jfg zb&5MivCZ+?b;pT?3ijBDr9&gNi8)Gf+wOy>?l^@topHL(Jch=VG~pc&9(!_<*~57Q z?gWK1J5Xh;i3JMrL=f3crOK?WrAv70Zql8kaAvHhozFbWNfORo!8wsSVs@gC&V$dj zXDC@R+vEvz-`x~@#Ol6fDcoVWS3yLryF)ED5F8UH)&1h`WTk}JyrpsRAWdlZ0FBpL zerX5uAd9`Y%F9kGvRJ9580)=>Q5V=S7B9lMlGTukw zOfSm6W*SFKPL_~XfRyuwskZ5H$*o9aSgB~HhnP-m-V=`E1h@)7&Y%d3$6%~Ro3oT~ zi(`AIDzLeUQ{kFw!J@)xvCKgQ3G}(s720gj3bY6m47AkzJOB732xD}lapor$`qp+J(CRPgiK(P7L zTkV4Wq2AHHb?!lmXpUEk`S{z-lcP~0PDl?1iF+n>QXx0KeAK>(#~5URunit7C%fWWDoef&|11~&5bI$9d9U~SQ4oM z9|N4DJ(=5=Pt9-l~$TZ8>9*CA)s;GTk>3CnbD}I zexED%Pz5#}g~}9KEn2jA7_?xw*T)26n8`g{!Oaj-u}zgofz~24ivfhi|09+P?Xvh! zSN(NBdH&|r8CK`G7Rzl>Ow(T|U7m?JDP#jYHd7%y=L3mzXxv~YCl%QA?<<0ITCk|l zgbIB8ggf*Fg9Auz9c^wMZO-Flte<(?ZmUwH-?AB{9lS!iXtNF4q><8|wj{>7DW!sG zwz|w2B2>uJAaf_D+P}0pM{Z77NnWh5rXgwPV-rf6@V0|@4AtStVwfQK|9FlVYOV1P zZpBv5e^s{B6MCY@LO zL95U0eq@FTqR=H!h$pSh&H8ro*+bhqrGdHP+{s^$afC#k@Y=Bgc+{<-I3ES4+EeME z>nQvNs{%>~UAb`4WdXYI@(8X8GC|x9#WgPlDcOR`i#yxQhXfCJz4?HGFDV<6e-xp0LyiooxklL8=4sG8}09Pk5$~&R*x;% z=%P>|KMv&Jh{XMNtc~5{71o@eQ*S=EeGhR0d;);%e+4^L%M4Yx49-1Kkxl=rP~a-j zqQ&LVf~Shm&Pc|PEKT|+T8_8f6-p0ts;Fr264|22lb{Gs6=BYzz<{c<}d>^*18fWz-I%TsT8{4?x zv@B_N>Xg&-0>w8sI%oY|;<3uBB#RPPK?$z=-e6s@`jB0ss}hK*4^EB0c=Gku=A-eC1|gz*wE*cAx% z%BL6HOBKhol!ah-K7^k0vR(#ah(6;|;~49Dxk8#Nm~?ie^A9;`Qow70;|O1F${y$+ z>RU6~*R#>RLP5=8TbLNj#0veDpz~amc-XXVb+1xn(=>K>+DW8PUkxfprwb`R>_cpz z_>6mvQo!^H()#WqS`>LL6v^G>2dDjYifVS?lAHW;-Rbo}a1CeYV>dfW-y#qC4GLwN zg|0aeL8_GPjR3P>iwUDqqemaMFUwD(zqtD&)6-%mK{ti;yN2)}C)wOml5i5?ss46WrT?<7p>&arx-L0A5~p*DJI+ z?NoSk1<9hs4N!tZ)Yzuv1Hf>~(`Al1>EY(Vwe3iEwnvb88U5$^qpYR&|v4iwfdbdo?nI_p?nCG;GKC>xN)wvbI!Yxv=Qw-tZ=4_RB8+pnL_>u$UHuv zkoU|&o4cD8*6ckqBq6$_TAm<33M5YXX~1;sWSH}%s>L<;ze03S`GA2*BT?!IBqBHVuSC51ObHkDgY}tTy)Zqcf6|C8S?O64^-Hg+-S|HQg^2$t+lzfy@aM+^>M+^%y?I#^kOBf>xU; z!?(4wP5r9l|*6w15A#lgoJg!zIXprKr;qfk*)5f3G82hvC$2%e!SK|XK@wHT+dg~Se)Sg z16*N+w6?Fef3Ro3{Z}!~nX^!(*~l2Ddz!saA^$HHG)A*AUGGCd$b6Qa*^XVK*(6bj zw<5uX2oX=Bye)KVMK-;}ZV{rKU{PRSD8NQ2TNH+w*WE_3P4}ov3R;jU*xSZ(2Zt~p zM5ChXTA74hme*a_$ZaYPuE`P?9B}0|7eDmo(IcT8>d?K;qLu z3cZ{?=2C(vbTAZRYw6E(j#Bv7(c1}!C?S(%yyJm%=TJhbp`o@2+U-aEdBQ79|dY5|tA(d1X8?-$m)Mw7w5wC2VrEwro}_?g__!o>CnrykcLkDu$bHAo4>ptB-4x0+W92>qWC`Z( zz?|$cRm-*f1G?^HrNRV#b;)tH-64sB_ke=AAjih$BE6Wav@jPMC1D2$639IP+0WNP zZIF(lx_d1ZP^@V$NC5W+fIVyW%_xP(AN{|N0-2t5yF4v~#R+Z&a2#FmL7PqWnFV@N zd!>SzS!N~G#-aqY3LtJBGRk46_f&;3ckbKy4D(EmFir!5tve0&^!8GppK!Y3t+x7P zYT!zR3j7SfdE|$c0?sCKu;xs~H4SU4{HnuDqCoEpXb289FA1mGcDl0^&+IEW)K*Wf z1}E2F#0l(dz_@GT@^f!YeWdLig)<{I_D}*S=er@3?an&)hoc z5*5m%3i$pxFx~ouy$*!r{ATV0mI^N0oAT3SPO5+(2ryS~_9h3l$yWCuMKvQojq;}x z`9Thd6y$?}WdEP{bok7!;@x*?qa;caOb;;JmbsPo!0={z3~7ymnT0DjTw0`1dqL$L z2JsItVTb>AYZch+Lw)C%<1IPad48O1 zgCd%vv&5E*FoE^Q^2MF3F@I=R(aiSjx`zdk!rTZZ`>t3=&op;Y_Cas>PdA{rrfF}m zjA(|6LWMjCG7pnnOAaZb=|2`*GD;KFFi_lz)LFxEEJRF46wUPLlBqJ0C9Lzo3KbgO z%p$Wi(wfHH=|&aMuFx)tD?zA`$3RYxu1+-@+ugWgnpIk{hvH{lflUC$OMn={qt!C; zHYuLD`tBOU^D>3H8C1;7@w_|2hH%vLVMB8>rP~4eT-5MF;KFo?S*xdU$-=a24z#G0 z7b&K>?nu2JKVRkKNeLe!B^+7I-Duz*s%WO`n9_2h1oSX~=!X_K{OWSwxO=#wn4V)v z&L^$V1yKWnM>wo&a8DnhAZB+gj_@c=P<5b!%SN|Kz!AWTZHr==lWu!4_jWI8El3hh z0~`*yNhSskI`a_lD_6fhaFYsr9#wSLby{UIMwxigrU`9$5Qbn>Z>#C(knJwFRViQ& ziHaDM2o&TtASry0R215F!swe)D04Mfw(XP~b<;rbG>_v$b$Ze^be)S8$sBXq<4@&D znYIJSod@l`iDH)YEQgy>v?Y$YoG1a!0>t)&FNBKc;oO{}nGNPo=H(_@e_K@)D9jd^ zoE{SlHB~iEOY%b4%`2|yvFSQ3lPd5_Vu8b-QT_5I+|DVm>9greLbXJJwgKhPFbsuv z2M{;Bu&-y-brf~AH89JqPa;&n3jpWB-&9uQYPcPWX?htY;qM?zP&;E8C7^-1o?i>u zrFf>dSQXUBL<)8hSRN^%_Pu+0sREkLaI1VJo_9y8ae0P<3A~VaF{BJj$-U|&r%AQ+j%p^l($mJ zqQQvHpwt+|`O{#&k>XB++*0 zh2ZhRha#bH1PAN8+=~>;^pk1!i6$rtl2Tm*3b&uPPn2fXboAse#Wh~6PVo$GUapYlinUOuNmS!nFt|#^ z3dx&QuTUh@aqMP>)QeTG1eSxU$Zc*=mT3O6q*p1lX#q0;^{Fnsx0?zrHARMR8~C;6yke8WZ&L< zt9;QX`P=VRKy$5|j-f=Dz}^QKcVzKlre|jS8yD|aIJ10JPEimj$PWN{yl?E{!4+Ll@T+xdhoBGwixk?gHEQ$Zcz;--P3x%qiA<6(J_1Hq0mFl#6;yC| zZ&oPNG8Rjj-U=hgj{+H%QS0ak1|M*7A5%QDS;@g(Xmsdd$y|JzvXVrg;64uAF}_)4 zBb9T)__ACIhvD^-Pbm6wPhI4Nizc6hCQ00p79qK~L926@S+P*jr36vvvrveA9@y5QmYelA2lwr2H0SXMwELV=#XP=Q zrb@YNQR4GZg5At4FzVf34jXuW0iSJm4LHH%5fVt2vcwf@z zvlp^ivgq(-=)iqa4um0gl|5Ac6{Ucgr@A$qbd1ZiGP#2PD)4OP!#OvK>wSN5miw-vn?|lnhsvZ1 z`g=gLiz5A=U+@0DqMF-emE*|E6W$NNV<%r~v%MPV(p6 zj}_7^<#Zt(FE3AUKLL&#RDvAQn7N-S=xS@iP%a5=wuda6C{)Nl1DShrZJ=4-(Hw0y z7HBJSM-zIwpDXkp_2d%4g8v2Z+`Je_WEbI=(|^vj+%FZ|?8jB3C@)pOzXJGZKQm^& zJ$j}XSVte#f<=kHK#60sj7S=zoOWoU#ifg|8Ipf z$85LW73B*5Kj5F>n>WmV*=a4ZTKN;o|5b_%TV*dZU)>p^)c>FqPak8`+vX@~j7G-h z`u66+{JKfE51E*JqMBJFWr`H#3j9_iJ{(TV9Q^F{;lci)iSa&nYo&s@&gkOhE7_vP zzEFc_5^PekPZm~Ow^4X=*4|1Ia_+T~C&=3Z$*T)YUKA=?CpT%xCU13KvZdgeKhAvM!HB(Au60-9d_P)_9k$9%KskU|><> z6l3BwCT{jXs`eoYYSuWJ%iJ?yTAl#!2p|U#vT|m_Z^Q7!sJoK_o6}gA(k7Bcg*!t9 zuIl_wfOnM+RdBP^X;f6p6Xan)V&4eiGn>6SRPE}Ii)_8^(cim2h(n5ltQ>@ax^qK%Fn35j$q}% zu?qSJ^3L1t7^R2V%_=NPL9!@uERNktSv1PbzaAlZJV zD-d^rBAS7cf^QgoPNAI$8ZQGvE#pSyHr>!oPXnE#faWrwqI#o9!QK^Eu2+BSNUdkA zwsv@84c&rsHw86EFXhG5bGZpho)GUI3re#VO-a0I&(X${m&$DCPbn7U3G*Ic@;m>>1p1`p08`?0WOUT4~FGVzisTJ**iWU65f#*PGn0+WEqUq*B zc+A~L(arUGItgWSS|U~8D*)%wBAamo&ADxzDYsH#&GA{e8OH*JxC%rz%(A_V`FMEE zd40X(?o>rxO$MxMu6^YOa}+A%(_&e(EL1-cxziQZoDRCAp?ZmeJOfA`r|=38JHp;fd5~M~C+A6Hsv?Yez#ZzzrBe*;_Ce+A)(&{1Bv{V&u z*gc*oI|yYt*eJ6z`#?iVAJfUJ9C?W+Gz=a)T)`9Sot<|h3T9@&SGYeUOA2;AKz#D7 z)%4t>=CuvYYipU>>eEOj&kh8F{njcq$J=p@tpK6%^ggu$8GmlBmpxdNq ztF7`>cjQc{6mK)gY^bE2Xl*BZmJTJ)MON7A2sE0mL1XhAN(2at~J!yJO}TH$jTXuR%Uf zYUv)SdxXN6K4`f=7~jhfWIZBfWf~H$wUPTS_EPVA~=rOq+mBDVS*>E9T1_Xc{11 zIQa7b(Ia&iE1KDAC3(hCoRn-kfIO~!bgQ3^330Hj?Pe6wtjv;VSx%lHXMx1Jn?iWu zLQ5pU_3i33=lr4FImI>o%k)0W3bBH30e=GFM;3$mX16TcZ}Pw5F^zep$8xruDj1^F zB~Xgn9mZ#btQ=|Ja|WE!!ff}n6_hvuwgF^=B+GH?hNJXWR!8wnFS~Ln&H{zF0OFCp z-b1VR?P@l#naYVal$X0hp-m?+ZTPG^X~CkxPN={p$_JJZE9f8Z8+5xA*bEVt#Fj*u zz!m}Hk+r^mfDRSX?Fk_o?JiZkC5|jDPmqrUlBdhyAJBmj=N_eKX6Y*Y0tge-Wk7N6 zad9tWu)lY7c&x8?cxbJAw1N*%59k`%*_|zo96%I$3>4x;tEA`j&(^nP2b&(N^e~M| zW!6t#tk549>G9ehEHAhn+~XD9?Acu}|A~Ty{{-;4XNToYSXVt!flc46%L*o4r(X^v zhfigZLPu0`haRs`Xmg{yaC3-vLx$wZ3T^Hh7M&_T8|GvR_DWz8 zWus|^a@;4Uw{CS$Q8?2dRedXp63SCS2_t!|*6uiZNQ9PTPg5Y%HdkDDCISWbbl`aU z2~i0AAAa036w;i2O2ZH$PJqt@kQ*=h!=cMQOA+^=@w80AJ{wq`gYw&ze4+=fz5?LVHKq$3iJ739_uIG;wcUUFgds3 z1&V*3WvGi|ri*w{<|-(|L24|Ke95m?3U78W1J7cG{u0oS_Kh9rtR#E4ROPr#{H00-v#HA_g-Y?F z%FCb%$4NM44&%Gg@tU;V%aso1#8jF$mlrAAYrzeUroQYn9HM-Mf}3rS4sySxHt%p8 zll?jtD+;_43h-o18%{pinZtLlQdrY`7t@^+fdYIrfV?}v+qlRxr_<`MQ9RS}E8P`g zVZwSXSZul3Z^r^7csZ|AJkx~DR=!Qm5(WBtK+}+$f3|XlUdL;@Hz@3C%YIajs3=s( zZv>eq;;`d2)|}bu-lULb%~ou5L71Sf%cEv#t>9x5?#)X_;VOn0&cGdCL71T40u-)a0AH{=na4-){rkc_vu=c z;^wEH8x`N&zN_p$@XOhW39?0xw?hvOR{6N}VAE}Dx_2nBnbA;^o9-nE<|bfxrVrK` z*R0bDn;up??JRGqaCGpUirc@(Ct%()vkl~*z#Z(Gfb&zO$pw}*uCg4v0TVTU z1~s|!=c9Sp@%_0{XNjF(i4)*208F;BX%XRmsaU2XRnhh&OF+MhCG!zd?*wu5@7IcE z_OxR3Pl*)hZ(`~ECFSfU{#Nl!|E1)b^2AB}9WXqOfb;uUA*!m>fsIczbgfny?D(_7hV1VT{udO(4~Kw_n!)E zRx%de(WMYMg7_B@G2>{YHShkd2&Y-buF#AmMdben@_Bj2AqkGP|5q_gpRZ!2l=oBq z2h>r%Px3XOo2HvPkvfjYQKq*ov=-WKAF^-x+%)sZkzVarNtW{7iU6VeNT#;G?t^F2 z@fKHtyS388>^_yb+9lFOmwllNcOQ7Im|5Lz6!?Bt<5taNkS3tp0>nX<(wqwSe~M}b zS#~RAZpj~OQJlE|WDiyDVP4esbcaUZVcfaxZ8 z7o~w287a)YB~pcbIM~Vbt2PcPd`wqR9HDd=SVpUq0Ysf6p-x&AxnQ$9N~y8uRgse_ z?4!ZP$e_H8U>Mf-*2YJBdN;ab6nM2&{=&mZMWMnyHkLWFN7%FucJ4TZUY4DUa)o|8 z=o~;sXw2_rP%wf{qMV?>rq56aiA7;TI}x;#sPeKbOc?e0&d@{I*$Z>_Ns2#Y)p=#V zuR@4ccZF7L>v=-UUe9oMQ%acbeA%p)i4)-60pz#`Qe;#>(kI}Ytia|JUYdZDk8?t- zC~yxbz{@7d10~0eyPrEnq0MDeWh!VUQ@Hm8mm_I@Baru!&vf@vNOR^X3pnQ`3h>?l z9^pG&wkfl&PIv2Ij`H`&-$$WM7q!dYOd?rSSW#N$Gu%oAUT&Gs5a6l^3~K;he4na- zrY~Bt2uK#-rvV11g|pe_U2D>vu0VU17za^Oq%%NauSHzzzFqSa&ZeV8XDXUGDRgtO zMXG@B3vkHD^ZR2p?8dmW6w|bgt@6z^2ou!VK~!J*7(*P3{G}ACSlU z(NX3A#dO|tl?DTrE#5sZC<90x+#d?j56utsmJ0eG@*f|d=w@KDI{y*!1ol9{j%FCQ zE$zfj4YfM7sG4ccHYtl}(mhDA*I6a6Xz8M8QRBf-gCo#k{`UhcO#iDD-!#S*Yn+@+ z0rvom4i|kBigqG5W6e^bMRTlW3bYqc4xDkUV1Cg}Z=344wTfvDsWjA{2oqSJlyGEG zj?0C^Q0o-U98z7b_e|{JdLVgb_4~Hr7Kk1kIC2{l)m%B2Y~SVuN;&%h<(};KuqZ|- z$608voGfO`wcU9NZtkR%Y>t%)79}=DB|=n!|Bt*tdbgEldN-hyFo#n`WTGfq)EI;s zY(^zPonGg{Bkn_rZPtF}b{z{8;xLHxLq-deQ%H0fQ8d$NRZUAQPhjT*#^VQ(cQiML z@<$cVEM0jhKNBdxF#zx3OIJ+vW&gq}fG^I~=}EG2rO3EtF^h`q7DyDFfP%+)1=(hz zQf6Wh5;{&&^KVjmnK3|ZNxMlGWi~^Z5VRVr(Tfjw0<+WdQyFbgqnqU8q2?H@n8~zY z!CweGyDOA;(WwV(cag%{s~9@A)R~^m1+sJE1ojZX=!g0}-|#hp7t|iASf=xr-0zha zC7g$W!;1!l(;FeX%{^R^%ozir`9>O>7h%GxfyGO~c%sJ}c=rf}vuEPP4z_9Pxui@b zQ>b-Nx!G#SU77R-#%)nVGx(QWVU?34oCY{*i)VazZU6fIaW|=8%h=)xB8A!nl`S&& zlQB7fw^cFCep%XAM4a%pfyZrFqr7(tYcw6FZM&(Z0+o}IiWA^8fMHeZ_dopm6wY0& zXy#t7qUB@>YCBL|m%&-2f$8)8W)#evZz>$sAWwj^0CEyst|B@A9ed+*3Tuvvw2Wmk z1>FMrSZ`k{q9i_bYhGz!x)i$=DS>EFNh7Bdp_+jG|eHp_hh!koYRP-uxrNyD5 zJZINYL~|LRx=^V!fh_>WTS_s%pJ(^MdV~DO9g1qkqpFkqb7BR*6Zk?6PmGN8jk;Zm zysR4bB89pLDzCi49uK9ow%pq39po^$OBL7b*%jM7Ihg`}B)~k1B{t6|#oeP6)b!#i zgPtroRA&^Qdj_8golvw7j`{X zAy-rPUgELfaV=E9j{`Wyh{!ng$wk8M@rt|0F`~Rw0Y4#v^Qk^#JL~iAi3)65<K!GMynC zej4j7_aa3#r_st8Et4tSYrtjG5S(G!unm`azgS_-fl=78&F=!UP~pA=+-#B0t&c@M zugcv^6?#t>`C72xUl#F*H?67j5{F(aK=ZhlFBM;9m6Tw?Ukf~YO|p0B2N%B?`U*ui z>%DUGFbWm&D?twXw76F#j%oKQg*9h_@(qfdNP)gOLj5WvZfd*ND5z;DN>(0GoB&@7 zAg{R6xjkI0^*Tj0eVOi)dwRdt>jCGbEZLQ~OZo-{HKRIhoogx^u2Rf5fS3ym4-o?KZp#pv%z}&LfJb+U; zKqvd%`xVm+n{B0U$FOc*mY_ZW6o-;x2-cfk@4Cr>(hn-~M$7z|_cgI+sm_Ie2-@%r z+FPG*FHqTYQ`v`=5@wY*SVpXYqEM-akANIK>{tWtW<_1PhaH6p?W3TvpA>FUz$CD4 zVyJh#e|X4!Od-vJc1brCp@RN6&}@f;YZ#7Ve?mb`J6vJ+(_`451Wt`1nm>6AeM%wC za&{R*B2>!xX@I$klldlWw|-`+=&rL43l;Qdf#wN3%my?Kd`Jrb7-eNCybN3oDl`9<-f z$}LcZySqPkM%|V6zq38?uPY_YdMIu^mxvYkHvs2B?hkfS-@}3ndm(N2O@%gR=hSm8 z2o&hI0Oe8Ut%*OB^lb&ZuhrArIQbnXh)j}Dz5`0wfLvGa)MtF#y6-NTvzR<`o=FnU z_rN)>YA{n*3a0?RufT&=0e5pKX9Q8`2T+Ks*ZU1Vy7favH&-Dg4hRGZg~q#G!g^$VcbcML|Oc3x|G&i!(!v;_`R#j%kWC$wLI#=|4i zgzlUCwSt-T*tKYV*-IS10geq#y3Qg$(*0IJ%}7VZ3>#wmBvMNGyI9Jw--`cpzgIwW zN-v3W(CZAj?DIbW#G8$%P8yV$cH)U}_eX^^w{)v2wjf%{`X{Im&tYOG`_Bq`nl%*L zI>bRzME+kOAN@0Kw^D3k+Wl2Q%yoI{kfqWD_BX(eB-qGeXt;ddzuzSPyW*NNV`(F5 zv7*2~q_jS5cSn0}9z%bt`=_FsL4gYEmPr)gzW_YJmspN{;%MLiW%jeXj}8Tc?*6S* z7@#k8bqXs_ewG77qyIo7Ueh6!+D8t?DTAursZ$2?f0Y(y%&sCliDG3^1^qvuIV|Iw zAAcmz$?QW`E1z&?hPg`GJtt3)w<58@LWSiOMcyao=u{tNfZbX#&BAsKy$7j6-Zzr{ z9uZE$XAe=`Mv=|Z7PpD=@`QO?Fyp+ou1VW}?*9~PkLNWnPEh*+#h!jx&+&^D2-tM$ zTipJNYSwLPKe8}lB30nG1Dq#S*yW)XpT2enD5yD%tIV-T6yWUv3?2&YiIGFiy~*7{ z5zP=#VOK1ZC9DHu;be-(`vdMEg)-Z*(qn))p&cA)A#K!0c-$e1X4?OXBvda=V0Q$J z{Y&q}=7LFgQarPCC9Z4~C%`*LpyXIf8rq=>X!e!LBx{w3b{Lq-o5gu6cNax8y|6Cc zECfm+4+oHERlhp(cP?VZjcJ8*u8&Y?(@!a`H!DPo5=TOb5F_=k-%-CFBtQ2kMK;5A zRq=fiCaj~u;>C47%COcaG1K$03Tc|2u0e(%RoKUZ&8-_;!e9xGQ&iL4t+GAj3bIH+ z9uFkX*kTYk@IbdZp5snX+|`!fP-zyTP$8cPGLKgw<3-n=@g8@Q!kWXU5*s86^R8fq z1i$+HJjKi4cO!F@L)7kWifo=Ut{k|DT;bmxe2zT(E|355_x8J!71%6t#URQg3i2L6 z@?1(T44pwC#qxpnQxw?jTJ5~UUnWw>_XL?6I4s}>7wDS9`I$v`F9kKNRmJj61Pb!r zK=R;~K9zO6GfsE+QCM^ER`#o$RAH}(#r1hDF|)_5R9tiZNyB1FoB&q=$emf-&n9gg zO*hCo;(|_hs=}JfomTnz%y8H$h!y;4vAn)7kJWd`Q{$&A@Dj_b#0l^W0D168o~7V>E9T4MrSNA%74F$_?~bh7*!XDw(0X@{Qo^)b zUH9xVxkA5R*NW(MOtlPTOja50*nw@%>`!A_X){S!vIrP$54A zWVSAxA}6=VyN4>O>8q8lp+%hV9tPeKepv8KLAU#`R+2*YaK$xe4hnK4M{dgHiUKt# zz*QZ)lVo4IM<}@I8F%eaB39USu(?a&CMBN|?02lUD6DA}ii0N;Ca?xzJZ^m0i#nZO zoFEruQt`~GswD1}lPAa~knDi?JF08_ZHo5S-ByLOZ9}u&aQ=qtXpr&}1-K1B`iWB& zE)sE5if2}5#asnpf|>^ED38Jp2DTY$*^PDKS;vbN*Yxqq_c6+3iyGUZ#sOXpe{nFK z?sYQ?dj@^n)e4qe8%%NpF$+Yn^HNguFLg-OApO`bW+u zwS31dG;rVfyrP@Np;49nm&g_VCE&Al${HCCcebhIoKnEN535V@6Um}N8!FHbb!mTN z*EFYocNEw3ij)tJ9TFBLpap<93gh?1VjSD;P%zW`@daz(oMLBYWqXnw(Cm&}`Ab)kT*orrDLcJ*g4p3jC3Pvn>okE@*;)%7;x#wJGu07$XIP)n1T+ERY24A zENnCeNy2#?I2@~#}P__fkR$>`|G8%WPxWX zxEVw#U4|zzh5T%gxogEp9UNl!90fJ~(u&%~3NM>22h;M3jdYh^Wru5JEP56I@m@hrroO)+MMz#Jg7{f zKwk|g*Z7!Z1p7N{k;OaaUZc2XjT@O1KHGRq;I9RojUt<4ERFznuTxyp8!xrQB2IX( z2QR5%njqSIxAhwoaZhVFlPJ(P0?IWk-HHc*-#Tz_Qe1OwS=p&_QiXjT*c>Gl4~mS| zn-$WWak}|WF-Q3=fQ5t&+RCqC{Q=M1y;bqd9my`+`4A|jdmDh2hAV8uU9aGK%W$O| zaW_Df&mLW8$s&k?NErjIz^b}+CP8Wg?oom!kjHj*7HiH zU~dAJJDfi@>Z6dD1*ATVc2Nm8lo9V(RYyjpY3id<5(hoInZwQMaCI7>U zXLhAVRWK}^l+e_t?q5~Z(a)O~EJ zl=54*yfC4B9F!A0C7pHj(+chriatPJ>KaKkCLj$EjXnvD*rBC`M9)@AlAr{W?e0^G zZ#uMkO_GTc(x*Y<<|MO_yFK$W3T3WK65Ei-64qy9srvo$nNC!ppMFlE%%0Q0n9e)u zSc|hTVSOGfy@vG1)4rf+=8RswhRmN*`yzmxage`uj9+*9l46>(dOGq80;QB+2K2;y z&s9??tqds)g_nW8qEr~My6*1JrWr)k`YP07H;%3lrOrFrY%I7o-2&#X*!h}L#k}FC zOqCMBg1;r=^EF4S7#~FVy26|5(CWqrA_e>nfDs7HA2iyvFyFVU)0}HhQ!9K^vCU;s zy7;b=D++uI3h?|R69F~O2p#RCMsVL&@YPlqsGJX?P$7Q@SsW)A*AVC-OllI z#WTlVh4C%!9{mDX-hZvS|J?mj(artWqHkR#TT1^csKK2S#wO(2{91ucN1I}1xkyx$ zB$(gC(sICspPovtWBILun%*w9zUH>Yd9_NiDDgWe!E4IUhr_8@$`r}&f&IPG!rc0( z=+8ybqQ)Pf2K|utyV+54ev{5#kyr6Y1vcm0vTcE!K*9Y9xVUV?Rwcy={;X)GuU+g~ zShle=LHz|NUeAQxADVEGp&f#3e^pR39zxqn&3wlylPd7P0Umr%e%}T8Fm3mD1vN`r z0rk=Z_7A}5huRR;&@;D)nsEPAEYld4*J=LG>7P&u^*S}w zY$90r{{f$S5K0+r#D5jlv=LkByK%5aNrL%bEM_`9!&}SyP~+zF)Xd(~ePpIjF5ilT zhy6OQ8F>s;yLbTC-CA+YMlC656ep$K7r?Mo+|)ltSMuLRam>Y1$wAth7bT3_g25ZT zSpYcLrP1a*<+8i~Q%u|DhCp&`$a2Y|!hTSJ8kPnMhk^Y}==N7!a~>~^0ee|Ox*bUD zp&*b5o7y)!-&u4AD3-lkqp!#ECBg)Dd%)<2iWT}Qm+KCSWg44`KAM#5K*0F+f?EHO zzs&ofrExf9@xeWJh~k-Jpd^DPiWA@+0c7`Ik~OJc%4~5b#Wa1d ziiFK5Qn+^pH&kf29sN)RGaIhFLRp${4g-g~BnN7J6^u=|yC|AH*HhwJr{sl}AW(pZ z1IWIt&w;|n_z%Ckc*Ihn6>TU21$rc)9J&az2o=_!%Q{LC&Co@~)Endp@Mr+JTD`4C zDe)if7{xP3dWoeLVFEiAFrIwF=CofOQ&I&V(LYWx%~>g3A!kSQ6R83}9&m2Y%*;|M z2VaSKf+DXbbJR7s*Jb}sgbMgXfVoX!{~C19^0w(V7Ud@?s%Z%t_?BBc)3r^UvAe9YC(x&}k9s332z671Xpm75z4flycsKBro`Bzi}=t?2!(1 z3jNb%?w&w~&{#NR&&sq{&d$>%QteuMVGAb_yL&112CariCm(~@hDkaQ?VnK;2(W1p^(1NGO^iQ|c+f8@6;;&wEFDMEX@);nr zClJbBYi+5`HFwebs|stjd!g7$qA>3Z=3RZAiwThSXr*2W8GuS`06_ z@Fqj_IvaX%e@rXPufJ;)CUfT~ZI<32DDvDv zda!KKqYrxU=1tm)4P5Tz)+r54|Ey3GB~pdG9&FCU$fh&8V*_bNZi51whO%;k3=##} z4=AtdQ`Mxuxbqa+3Q5CI`FFKt7+tP^-B#pgbH~OWcCxK!rN1I zvOPlzYPzLWwe7_TZWuUj-)Ne!@}o@Z5k)ke#6mH(NTHq&YFPtsYtrSj9XbOss@ThI zU=b`Dj6nnTj_HBusHgAP;|gx37!?X$kSW{=aOr0sa<%H@@`hlO+oX_Y>nda_PH3A! zE9=H&M4f{k`EcWMyD@|c`9hF6Dkj~S`lGu@A#deoptrTc`%6}^2l>mH#r*(>goNEcn|&;?D; zeKK6D zncXS)a(gAo6mA>bvYO{WRNHkFd$~0q;zsBM9Vtxl0v$xdqQ8iw=*34)jACR^oBcL8n>wC zohp|D(gb!HU}ZjszbM*0S}~XFb9kx3ehk>9vkjuxk5%Yp&o(4f$d3cLYioL9X2o?>V1P#hsA8v_z zvZ61y^&wQqS5}c56r*xa*~?@I74lO-E^GJM`Yw)-Jx$S<+wLM*G?T*F7By>1GF|<3F##umD!b!qZ?2iZ9% z`L*4v6n42?%S#pZtE<@4?b^16d(B>Ed#S>HE!d?doL*LPuT$t{oABIoO|J);mn9{8 z9$37&Hz@qlz4HpmQu;SS2Tn3cg9_f&E;r^nz)tE@(6KzY~4emFy9VlS!W}!iadJv4h3FrXJfHK zzX|lRIeU(B;NPjxW?w6mIc-0ZDcpB~%Q4`hI~8+l-mNrPdJMRWbkXHK1X=K>kJ_Ed zbDMKJcF;!Ud+8r9bMFJ67wQ*|Zx|k0J25yi+P7}ZyM*Di!uI*bh zvEF@Hal3Rui<=WG;Ew?8(?31lDB*Sjy<#}ulI=U}0H zWeM!#fcZToZpERok-pw>_X&mTvQ25>`dOp^KbZo@#(PG`Cq~?-_8u^Z6yT=;^k?>b z2}gS9`o_;FT9*`4t9XznsLulBk34u(Z_ilY@J9DJ1?ysxEf`A_+~dj8A23;KE|#(UNb z^to^EJ#3UJ*zcs+i6OpXgWCDKdk-6>3if-z(og7In|nrwXu=$G-&fFObS{x8$RDK0 z;Ssv7xBsF(_rtx16q$njQHn%IT0^GL{dn&oMW!HsLZYK@)S5^7xce#n<7Mt=pn5ae zOZFhzBcg6(}L^c)N1w~v?RK$JXz+mw+jZt{RTXvVA>H8h5ZHR%5% zG}ruwB0GQE*>DxICF^NynFVPSu9s<`p9az5-Waio(^KJY4lmdlQKM;mq8^{Nl1A z-NzvvqyZ~&2KDI%C9~w#+4&O_v*EsX9jYeIpzcQ~>P7jTwBG$4&;j&f5@s+DAPf&s zpTvR*>vl0b(4pLfUyd-YM-4rbWgwqn??S^9caY63hX*;71H4NTW-t#X3|IEzn6f`rG??WBZ0S5PpB+Y<6%YY{5=N2X~kFe-J?5+b< z(hTU~1mbv$h6k*eM>w1V^idLKFjo_XD%RA~+?mm(;GI_#OzWi z9N+;4eodS~J&sT`24HY3&z#1}ET+`s9oPYkfrdbXdjjDk!UBWt*@)tvpE-H{BwlYi zJkdcOph0ORHiR1Nlk6?y)Q_6}$qw=WZ`lxNaMuuyN;sC|T@2Scqys2nlVu=JA&96f z^-~Zf4o`J32bctLhC`YGJ&iydBJo$VOQ&W|E{E$J)&Ux?A<*DjgriX-qjhq2e(B8O zbU5VD4q(*O*%tRXGjfCW4qbhW6Vj(=;fgND6Nx}@~Cc;Q>#kc^+ z{LK#NAiY(IGpJ_}3hqPdtvKp$acG%f_oz0s9#e@1_)HHtH$Qb|c0PR0rw&jh8sPsU zV6})&EH5vH&vjr27?0X%lx9HBB9K@jVhwR{9CtVe7#wO^L72fzr1z1Cz}Xq>gPd?U z2YH_)&44BeRMUqsEH&k@4z3SXputTOu09eMRsWuJcz0nWszd|4)!uIbcMEHEdc^s{ zDTjA}_iG3=xEaFX-&JQ$FHB6{c7AF4_A}UOoes}-fCo@lPNYHJW{^>xC7X5ju0uMJ z202Ga*?y2lJw1Jvu_U(ZX@_|LJ6YScl4+px1id?&_B6bV1&4DK-+z(@E5w-S+bLR1 zRJcm#Cl(f_5#?BP5C>4j^t_@tgIY2uQ=E**F5h*inmB_xLnsN2i7T))J2N@`v}558 z2X=s=uWB(0G`O>bllYCmMXQvPp&pw$fT^QsD$l^4L$JE1W{Y_EJO_Ay5om2`G7a?e z3CaewKUkPQio+pxQH=Je$9%>3!F?!XSvgbjfPw?VjSp2ZH^bZ7^jXDZLYx&-5TZM`W<G)2c_Ek^$E-^RjQihv-6>JXb0F*jiL-< zj}V*!w2S2yhSSJOy6A8YFa_%J4D1rYs7d00l>pskhjjo=QWIxT`}SVb=a!*prl-zN zEZ!RKbXW&?uev+~`(k@9U0PrblEpkRSp-)fWIj0BF2{V`%6NY0^9Y$;x zBlqSd4(I@VRugAXUqL9&u{hJ!)_JMJI>1=0%QLXABp8>_QxkVgbI_len?Ai9Ugppa zu!J@Q8r;hXS2g40?8MSic!dKya5IWHgL);Q1{TmG;Z+Xp07JjAfF3cxuOc9uGPZM! zynMC8J3v!51RC7e41K?2;nfcBuD;(f1ANU;z@y=7KgEDY4e;v-$iWiBpeGmS=fc-J zv;z#5nmB{{27`)SE5^Y$-gT&&ID`5oLWv7s+h(AR5Wd;r9l(LAZ(UHPfqn}?X?HdD zHO^ym7f*!OI^YA?UBl!W`0EHx*F#JtUGBcsK_0;MsH7Rtw-JalaB*U0X&MPii%@7w z;q?yd05h;5(BQtEaJ0A7AHP1l!2un>-io3O;yaoUN5Xf0svwfu`mQF#(eT}$Du^_Z z-`IpW7QW|G1(B4~_ZkFe0MiNIbk`xGDC>*wBSdl^#2Ed42XX*QLq>6Zv-k%H!$c>W zQsO_vnfhi2cz{HwA!6+ff6$=gg44*Ce9K*j9wOGDe~8ev#WO~yf7pQ@VCqKDW^npP z2uGEqG0*993ya}L9o7L&M)C#h}5DJFJ7hS2Jqx6V3OMD`9`qVIBCrD9zsM zrwGKg`8hMw$aK+M(4Tfl2UweH;tc9%2*r6Pz99AP*D)r~Tp z{__s%06o!%hjY5cblj(vuAUqBWr@~wZ_K^>sa zk}zw;Um*-#CH2>4PU9rba`;t;bO2YWF3-SzjbI!gjeU~v>kjPz1Ee9);C_Q}^$okY zLHL^v?*R6_1-+X)gug|=$~Th<5PsXC9bihUi!0*n-F}BqY)Wlstw8Yg=WosMN0=L^+t5so;W4{vR0`@15qs{5==jO>+oJ3h3Y7t?tTR*=e;` zS3CWF_$$ZZIR0qFJ}+wac0vbtt{%pH*KJ(V*V$4YUg)_;L&)SFYI<*X?+41eo*WK626ar(HN1Q&eu%WWG(DotK@8Dm607P!9_ zbul_S=#jr8E(cU^w?zHMey6qByVR;aw0G9FI{g-Euk}Jd{Jmp!JDagAcW*g-81;4f zhj#Z-*k$KXFKisP31*_SY3x%DMM_GX>Rl@AkBd!ZQ7DTt`~yj|r-`lHTDzggQPm4A z6j8vfbN%p-j_j!`lidqj;C(c9V@9|XjXJfwyfDp%SupHEYc^o!{Szs2Z7ui8)@ple zb#JR(qCVt5J5t9-lfsj|&~0xW#-$wrS6i-@xYAXrHHAu3oMF{~VnI5fX!nbDF_}=y z@Gqpp`ch-tIx%c#9w{xj#lz$@& z?psNH!|pELFZI^D9hFRIN~u&bv`wndCR3oM(w*uRkN1!V?U0qN_RfVC>n!xcdmVv{ zvaV*_R_AgTy?efmJ5~1kb}F$ZR?Qv46arI*eV~G?+ z9|uK4o~ZpwysQXi_z!~P-&MQa)eBo4&YH5f+S>~6cj#kSVJbqgoj8duP~qtJg~62J zKS_YGhuz+8XXj`OmwsJp@s5fB5+86R#z>@6F_FZeNP)uTWS5Fb#VBU_{XH&?|3xB? z2a#22Le5ci&_-*0Z$~CtUs!c__Bw0fgO1l69=n3tQ>n`9$_Tn_DT5+0xUOKs2!%5I zH~DhRb}pkDOrO^~_rr%Av5ci&joF$2bwA~t2|j@sUC!+gSOgjH&-;MHL0uaA-kP2T=4 z43YNM4r)O4!^a$pj6Gj9fU_a$0%fIKQiMXwi4}rWhW{Y}c0iYx$!~47P@yG!e0+SI zS%%u~ZuJktVBCg^1R-sWn!t0103f&3%V;e0KH~l@V&TQV!>Ewwi}m()cWb{4|4U{x zvHE?m>V&ep4yDA)Q$OM8jo}ePM(iUeOd5Z(CcO;*N8pD6*haWcC0n?{RUlPQ5E~;G zVc5KBN)`2`e^wY$89ohAQo3Qc*TYjkj*y&2h=pp{jaHY-)bgCK(}H3>Ip; z1&3WIb{XzYc8^3u$-=GOC(BN&9X9r8iS@%h9KlSTNqgN3zJ2;obzJGFk0k zY^`sXEl%?7ez=c=%-A7jS3-hfHbsd_pMrj%2`Glh$zIro7a-OV(K?_7ee&r>CG~a- zzt|4!MC|VLwt5?w#`hy5Mzlb&-J+5T_jhD6 zHbDYB4F7L$S4W<zXJc zf;Z&}#+-gvL^HGupFwo`WVj~`_Hw_shr8($g$FqbnW<|OE^lug>bEZ+q7#}1=MdRq zAI$IZW%r2R)7l$jqy-NBD4A%iSw7bJE0RVT_2Droug2NEP@!LW%w+T5Q7z6 zV~+p&Zg`l3&kRndu%d%SjaA8$+Y_fW$WXv!gZ8FF(}VW|eTA3;Ml0z&oOHMjb6GG) z<`IrdCTCoA79ZBGsELstSjKOvVQ@9kXm%*sbwr#HC3vKR%d~uY^=RbM;EllY`YKTt zhq+$p6uq5ds-s^PC(RZu!=uRK;o!j~i9v^!`r0j6WQbZ_4v%(}GPbjpCgM{{WQ0f= z4JRU8^eoHp*(5?w64L;^x3agf!4`RpgTE1fF=9f*MS~{4;x{CTAv0xi3&DrFeyqXr z8r{lkEF5fR4B8aX$P_roUZ~5H7hC2x)d+YTk-0!}1UwH>zVLVlnu*P%-WSEz+bf}I zs@|uxa|J{%wJ(AY;xYkV{$7C9OZBgjH2zT;obt6d;D*EyY=7P+ZIKsIr1Zwh5>EDP_2Z{JG%8iQV4Y z!h(zP&(}J>$4B!`y*p}dn^2j#nAZH9jIZL3_LjJ!Pazd9{Ajq<-X4v?r#cduAyx}R zT0l}qSdu1FYSBWdaIgqbhNlr$R2wv2KYAMBy77^1Mh%7`Oq%4b%prCqE?kR%oJlLa z9xnHT|9Z%QWugvvn-~JFxvTo3CQehLRW^c$G-v50m*Fshd6>K3*>3M{Ld_=I;(Es* z6LzxKbqZuarXVdDQl&_akOkM#wH4NoO%#qg3Yoq(3MxV0z9~)BCzJnghpHxc!oK;46eS`9Zltc<^7FE0-&lKd#P z>lsQDXAb&14fA$n$k5u&ZrSIvCQ#j5}gek zl`=e`)lII~pW_H*0w?y;(2lZ0pbVVAbJqgI+{&W8vVw}mU7df$wNdvPIJEEoBQF|p zbV2M&=FfGUGM!#&0~gGx$rGEZz854o#VULP>V+~qizKcF3EODkz6V2Gj0LW=S1b&4FQm=Srm>{QGn2Y;Y{cyt37(+!gm2!-6i8N7@7UP<* zT{)=9Nn*=v>@tpT+p7IA<=`_NW38|T5%^gffgft}LfLk8mBz}&P&`PmLXqb`z75}(y(ppg^5Xs*e(CAfB= zBO&z~XB}K7wrl+j+lebmM5|;;m!46%MK{LY=Lm{_DcBI(xgSnD4Xakj@6umrgB2MhXdY=!7)m&FB;riw4By=}nm}NLa zI&3&`2)IWbZT;3Iq#g9b9gfs-{OJe_CO$aeWef-vJZ?nS-HJl+%5av1xPO#1JeFOk zJcJ!vE1mLEr?V4vem}4s>v8b;(d4XGO{%t;ed3PHO z4w_;QpXYepaAjUqeo9S{sFXO6%JBJwx;sRbVLyCaf|IgV&t!lwF{~M9 z$ItZ~hA$)_jawNTbysw=2Uq^NjzY%7A2l?*%yZWOZIs(dZ?Fb#i>qmP zo@0>d5gVgPi1tVNXfg$9j!1M2D|7GyS`Ob;pQ%IAP1N$z=OM$YJCl zY+(CmTb$N%d+P}!C7+{`I*Uzf7%Z~!s`e}M&yr$=Go<@=vQWu3mTW9Ns|?$u&J>4D z^e(bHTIgMD_N{hyaOc*JBb_y^UCTX(vouKSu8N!R+x-``i9M83O;69_2>Mq0cNrr=YeXAC&42}!qcvnz& z>v3bcE=MMG3X^N(9NsrjJpVCbyJ^JBm9hEVbwWb7Z zk>+>mh7jl$vqUi%zm60*4$?Jqbg9GFI|dnJxYAsR+gtLc5@^U2l%>5DP2N$*{TqnR zoasBeyNKZQLUP~x;Ts)=n40~gH-&F?c!x*h)h7Q<3aBzR{oP?7uR68-RbSDAY{+TWcW^po-qyVwHwK+HCb|V$FIt9D^nr#mS7rDv zYlO>d^b$D4WuAYxqmi){j0Pm67HCS76XDZIcp2VkZ@(&smTX71AHK)IW+K4|T$a7V zaYGim~a#LCv44a@I$@R{A1$a!{t61%iBm%E%Q}YWLS)cd?4sD%!wuH3 z+Nhp>kR)l@!b02Uv9s_N$0*}htA$`sDiQl6p%>cHceo>Kv+aF&ec^`)%#bUREUU?q z6vq!c7Gtc=ma)0X(9BS&nwvjyE=`}RvwnnhsK7MoDDn7F$776vy3Q0~#`v{CngRtw z(~2taA2aaYr5&UeZ+3SB^IgJ^JMc_KUW!`!_+?Y1sL6RlDHb)Y<|l|R(ZX$>hKpxm zf6}3k<7DFbq__GtVIqBLZh671qB8sxK{)`hX5$znHa&XlafcCWO!#SsK1RcbxOq5K zpuBku=|DjVVi|shBxsr8Z0qg~sn>tjfsdiFDImRiLz>8+LHX_*sviG2;xY`wjfyS~ z_F#$(~Fj>q-*-3aAavz4OD7==h$2}9KocnkI} z=_o)A-`P1|@{l99S|nL89&dYFlf%*Q%Xgi_(He)N^b5=~Ac51JORc4HACYTWKB$v_ zg&b(lF!+s03{H);(8Ha55Tjii~!+)QJEmel!APbJo=+E+?RNRLQzv&2N#%AR*L^-vr z&_T(X*-;&Bz)a#9t7-%Ex5$cGlHJnYMQmyfS<}Dm_+%XF)F<|^PLsMgS&Ap3>@xh0 zH3VNp&c4%rkk<&m>wq&WWc}&-rgi;$l`8hiR1M5_xKwk3#P5+32dAENw$-8^-tPEh z8p4!@iqKYY;+zxt`$XmPyh{I-jUXm#c!vYcC~CEF?Rf>YPby7yI6YOq86XK#vuUo+c(&EGSxa_66dyGEK_xC*;C`(O$tYL97miESR(v{?t*)ENiMl zV5Qeji930+Pcgr>hQxk~ubmD1GcussupE|}5BBGdM8=e|(K$3NrV=S;^;z!mO{^d- zzoyo)gZCGtaQ-!_rPDBZr(={+WX6aV?pkkK$1Z*tE?N5MG;Gkd( z*WRth%U_ZfRhXtQVjA@kh50MTWDGZ1(m3Ohy}B&voJq-##5%jQTtWXep_zVz!O>}N zGmOBCeN%J1%aO>aGiweCK*sVxL-lWZS zgR^!bDGC!)W>%A&Q6__M)L`%t;s3OdX1du!9hJX#h?&`8?~Noosa~UR-jrumaQ=aC zV%Ta#IxZUj=+H7ilH>QQ+pU43Ju1c=DdEfu+NQ^NTT}p@- zDL7LDap->`1vUb^I30=)|2jT?>SU) zdfcrKm9TS+T&Phi!sWoft`dFCfJ=u9`rOl|*(Grr?AKWVm-mpPc;Y&TF2UTaP0aT? zy2pVy!U#9ILndZZs5;^TcUI7p~{7^2%X(ZN4?*%7-M&n&ntRelDyy|epS8qe-iN#Xxo&jx6wf`0G=U@ zozB*7_<%znW5F<4%D_G$GrA#JR_$BUcLmW<-hzZ42|}p5fMo(6O10cr0j3W+N|{q1 z)eZ(GZ@mE1Xz}M5ip}qycWSwMpuJZKU-Y$+Z%Xa*V{MJ>pMKGdc5#ZF6B?bHacX-@^mu;rGcp3p)O3X-4$wvOUV zWl97I4|DLD5Rx^3O3?RjN^72DcsL=k2uS7178)C=InXYcdyjCSnea@d<_442XcyJx zn)i1#ftj|*Y!NBu7#`^mGkPqCm;{P8#hKBVj8bLGVab0K;ki$2t5u8ZX$!@VV%?aO zkBvN2lr(&_iN6UjQ!{Z1|*O{d?(trq$clengZxvQ#xf`og)(|HEC{t6}izrh; zU@k!I{{GG?586kYyLB`?(V>rF$(s~ye*09(lrdpnn>keN>PD{lGvvu;tK_=)t6+fTXDD&r$n8b>75 z3z&)T*$^zlp{f$Zz?eLhD()R4Dg2Y!gY4CQA2}Ust?dmIyKtN`(I{I52I~UXCCW0u zV!#}+gqho@g@$eS=6mt z;ueRZHpNL}bK9d6CKRB0*=Lafx5d&(mKXt7G<+k;lE)pHlcV3?$e1u?W1mo3OpBnI zXjvN&6_G$g5%EwjgPibBlhqODXBG?(Euv_KyNe1@c3W9bxRwXQ z!;4reC&`AId1r5HYZpNgbP&pCI3k&Kq0-FhCvBIyKry^dpP8N2>UdJla+=7DLU0Mg z_Eah>ebRxCq3vuHi~%Ai(Y%yf4KdIFu5FE;a)_CBw=vMruTGx4)uLilV{wM)5}iW{ zkG-{S4+Dld+euqJ+p)-mqKri^ih`s#7>COin{R@kIB-bNiq>tUMVlW%dQJ40bv&Mg zUyiWo>=^}@3Pm%lgjR+*inZNN#{VzxqE?2JoQW|c11!ec6@dm_6eiRDR^3E^{;fPi z4C;A;v#F!`75|q^n6Ti8WKxx_sfXBJUaU-b{Sx^K$Q7U~SBBe-4aWG2rdvw&4D^4A zgB$&@=-6cH%_Xr&yEIog4*C(&ZSXIV1(h+{hx*Uga>wSyE`M1Z}xKqs3hvHOQ%y z>(TLpuLNGSdI^HZT_j2U1E=SZ6E|y_#NJ{_{eJj7M9|#Rxe~@lriL5NfHf+OpsmnL)tC+LPGM?Zwfr3 zY_CP-p6jqP&Y8XV(5T#YB~ykRKc|@7c{1Q6(B;O?E`%>~;F<84fhUUu!Bt%3Q%ypi zpO0r0WZ9dOl}!sKz^`wU!lR|r;QALEVBu<*RJIPiZy&d$Yd=t&tNe79j_xDe51GcCI5 z$Q&QtUuk6;bWT~gst=INPkidu!|IVNK?i%QUTX-aE`moFHk zU53zSjfj5Oa*!FFRSOaxQ^2My8Fo_hD=Tugh2fXVspXP!z75Bx1S$Mhn(5DVfB*usG`>7sPnA1 z{vg{`&!+T?lM}b2Y!`9qoE|;Kqle+5gUsy34UQ~I(3N-K=;9^fa6oY$GfT4HYNOf$ z3OfSyvIEW7;b|_@E`ff~TF7xN7$RHVUDKy#iOPh09Ki=F0%qjIg&~@iN!*%L){otP z=lJBT`-fPrLuCuOC3}fj&^bm9znJ6-kW1b!8cWKiL~j=vI_gha1%dC5HpaQh z@G=LODc?}7F@t+Q5T)uKk!So|-}iYr;kaGV-`lnG4y*gf*`bT71--&69E*&1q$6Ns zHA>SlFj}-^I4vdQViL&M4ZF1+R#@tE5;b9zLm6I4qSV`n%jz^lkw+8);p7jmaty~X z1fm#aI7Fs&K5E?>1`1t}0e!YAF+Y6u_`p>M(V9hE4yGlhT&xpS$s9O!{WZj;HDEJY z_w`@xpfeE_8;rx$f(Wxn!D|SGf0dhti!7w9CzKM1>{# zmNw)xOdOZ1ZzAU1@V@Iu!Z$m}L-=}xj>Vx z>ku;jy&d+|-*H@GBIfAUOVA zg_IU#uV5Wb!|uBsgE6#5impi6LoZQqV&-c-f8~wjz|h5Bzq7u#Wv(JhQ#b}0H?2{c zLf_v>6NEE@5bI#_cCPOwHVw}>C+%oC4|4Fdd3clKFh-22F}+8~wVFgYSzn!Pj^-xg zN>Wt+`$&#zm3|8AGFa1u?{}=mFo#p$G$LPKvb54vgiFz{A0QE$xG~N^%iIjBH#;iF z@n=`ie<}sK$_A>0LTW-KC!jLO>Et#|^k{vdFa?=$>@dNA^NU+)JgxQ?M{A7HD^IfJ zm6nqz@6TI;h{9bt>!lweg-67kuVJ%(q=x-j}e(x zAAAH@hGOldQS;-D#Te)KT)~VXQUz_ILaP?JpCA`Wk;A1&t=$V7;U^t|j6YC?YGaOB z93Z<|4P#l)CvT5}~pe4;>B2Mhidf$Yd0qt?7C0q+z>ZVg1HsG{V{XrRij?8F3r_-Zr7{=k}9jnabt~yWVGe1VH6OW&^ zC{gZ&O9xWfFU<_Ew-Jtp7yLF%?C{GDBok4vk(w4BF$zSC zycsk)Bvx9^#!+%)(mtR~_zgP#Q4~N4KsMD$O_(fhr!qMjm=gRtw3cW&3jY zb%%caXmopPt1<(1qe5iI1eLgPKYM-OyI2wkRI?x~t$*0vboT7cf74-SOkFhuYWYlwN6v^z-5o+I|DQ!k;?=8I!A8H1&quYSr{o#qdS;phATXYE)qdFlEjC1=%oA(p?Yl zboiO+QkfFNVl&-!c|pE@cfB4E{Y#?JnPdEu7an7=M+Ib!5YiL=D@S1rXRZ-z93l5y z0nD?k@iEg!{z?s-Wk;}b0vmDZza~9f;GVyS$O`V&gu%m#0pVSa+BkCtHehn1Fg{vN zruap-D-InN;*{ZU$bufz?!E<$RfGPmV~|NHQVp5}=m_o1mf_oj?!&-V1%ib_J0l|ze<*OC6$ve z1SEqH-sXhW%qgIQQU>$CS%ah}_@KUT{2;53rO83T%XtD+!XOwGtDW9c)2<&r z=s+_@h=S4yuJZGoI6=3wfYpfmZ=&W)2vJW{586#1gq^&Jcu}>{0S@d^`Wnh;a;irI91=PAADVnA+?qsd;2}dPknhqPFO=&U(Ec}$( zSq_%Q0z6hq^ZCz1JVsIYki8XedYsb5C^;UJVPQo zh8oyMvMAFN?oN85C-zVi4{4{?4fk*?GkU^C#C9LXr5ze>ij(phOZuI;awJoY(R-2z zcTQ2~Io!*EKV@_i?eSRV;qCUSwh*2c9ZP$BW@@?&_oiG4wr=j@fGm8}`#9m5MYl5I zhR2+Dqf8mc3-N=L>40+hbRvu4rsW2C`AG-XBrNjvHY%gu*YOy`aO15QR;m=v2<#l* zu~nBUfRpi8v-p*00|6|<{m6(@&K#NkW}Ej;-`_FGOgZc8axav2@o7`qId<0c<<-5= z-$Tqm>I`z;V{9@5)&96p>@qwck;0H<>@a4jJIa?duT@xt*r)g9jhcOQ| zX}>JukVjPuQlVbp?lQw({qP{i;>hTcXiWqERL5eHA`3(GI(X+NMWbIZMv&}>S%4oN zOlXF5x@#%T>>&<2GeD{q7(P%dsS;3I?8qU&HLF6!j={{q4()nZ(#SrObhv=8!H@54 zsIilD!$TdhOcu8_irX(4CRXsK1Wyw>E9LN6q;pTuL4Wr8;b9Ixqd^T{9@K7;A0@_a zhI?G0F(#JwQHgZBb`{3MiHv_zQS9hVI(@Z3TX=+{k?~P$@tk-q2G5K%<;hZs=vF7F z{OV$$t4V@ZLoGxZ9_i3CR_m~JvL;G^>jBQRP(F&lG7NB3U(eU~LOS;IXvg3<7>-!T ztQ!Wh*t}3NDD{LsPGsqR1E$AklL(h7TKS?vnXQS$#>b4$q3%0a8|#R0LWP5Lgo3b| zF6{Tmk^`-%v}0_!p|)lgj!Y)M%^D=hQYPu66D?X>_n@m;@i-E?2MEFV>W9ZW@bU7T zW8ra1kgctG9BJL|-YMY@wEGhX@kl_VARJEMYOO}Z66s3z!xJ6wEdG4NFi27k51w{M zcudZi4giSlAUh*^vD-u#tcK81)Jg{duDnx|>?LBdlVi%iHP$r$2Kr{6jG zIzw?^HTP?+`UuKZke8%~?C3Frq$aL&d@}Y{KFl$a`734@7qDA~ip_{wAv>m&6PK5G5x0=yIQXIrhslomE4?AK7+l(Lyr>o8*Xt-j)Uz8g`d`3okg{R z(@vW5s5Mr1Y&9j zx7koTiYpC{@qDg>%Gg*n3opK9LzD<#j5|{B%XnJnSp=oZtR^v%8c?D#9Cx_KN55iv z)}LQUztDmveX)3D-p3+}(}E@Q4(?jK_zSfqtSJJkGpDumgrk&ERMzTg#Awqu&R+rxnq$U~}6Q^|Slej;yT{$SC za2a&;dSF`O>*}E5S!)7{3txGO4w^QDTB{v`ujpI8(oHn7>oI7U2sV@I3x`=Y`SMQ<7btM(U?5oh3Luk7Pr^1GhvxMXyIafu=n-N}>2pVoWra0eLnlgn_P z*i3-LhTLA*318$OGd5x6a1I{pQ)v?Dp~I;k>$xm#;);Wftq3^&G4(jCjE`@x%*~8; zJgcTZn>6Y8_`)b5K}gBOP%>Kgl9LhaX^Sws$%`gvytAOjqvT-5?eX!=w~q?enndaL3rM zHyMg;pRAgCoNZEB9ZoZWxmhBq*;KO6bATD=uNq;)W6&m3Jmr(j{iZ^b%#vE7{smIt z^rC*b(Aj5YLDb4bg$T#wIR0kDRIhZ*uspt+P}v&3O+gAP!HGG(O%jYZuOKh`LfCQ8 z8TD2*!r(L$VY0MymdU63B~yF+9pWDeNielHF518_N^^!{sLlia@m!Q z8ti+a13x|*yc&d~FSyg>+s8r(^+_~c7f=a=N8V=`UM#L%*k72zNuL*y5VdN*(+;bf zt&4pPiiR(DlrkE|+QSYLI8kCg=y%sXrMTEXR3I&8b(2?WznJJ86mm$373{>A4KH!v znJwNF%{ZJM*E!h~DJTm({glF;GcFo_7Tb~RbP|7(@ zK5_hS!WFa8!D%BWgvYv($Wp62ha}zARKo$2{gq@yLwGgp?_zCv)%bjD80(Wdi1cU8 zoe+WO(A`aRXJwOpl_4IzK`Q)wwL{EUfVCF5Aue2_%L;uBaYSwLDr!5l`D%wYhPj(g zI$;x_DlR7%Tt}%I495l6@tkHEUef?K-Tk!=JY)V?;}Qlx$7Pdm5{1dD$)(yFbw*!) z9YMvpDA%~2#gp&h>mBSE{*+J9tILZKjU*q%8VF1?TeE1ZWaRLT4mxA?+8b9->q~o? zvO;sGLr(101Fqj>?@vpt$|eloJU)qJiVd#^S7j((jki6Cdzq2tQK+NSxc%u{NQLn| zQd#SU@LIkx(27^Frs-JK$gPA*+SEy6V4n;i#c~fdrq=pAQzNTC-k}U{ zBqM4R$x3YDOl(XO58vZBW$a(gXl&${dvRiYo{@XuquEzg!9y7dvY@@QYv+B!n;d*5 zPH$e8>Dk^CXyHbK0@LjuHXtN0j&qCH*g9J`61u$u*XoQQA*SygE9r` ztU?u&IOU~KW%vQ|;GwHzFUITzi&(wck;!BLBoU)`*3`$3vZdoE1`;EFkd(Nful6s} zchpKAZ*e>_iZxBMek{;k7bHf#hN|g%itsZ05HU@wQg7_^E`=X2yA)W&Xw?#3qc_)j{xOeEI&vyngE zkS6lgG%prKK58`(m%}KIwtfo=?rck7*Ov1<4{ct-)q2Qa?j5wkH)Y41v`$ z{H#ODtjYF*rnTcVPO|Jc|IZPn9^#G363A3%U8kRSh-28ixzr1lDtJ@9Ri<8?6r3u= z`wRBg)sfv_bR3SOO-3xwRlsC;_%jI=3U)>piTT*~NP&Z2A_eL%E@^u^^!=$#5dcMT z4psnqt0R=zXG)WpN(ZMc5r4f@P2?fMC9Uj?fu?w9A!SC(@HTRj4L}CkdYFf(z~JbN zF)Erix-mc$R{DYZyuat!JH3Xz$OV#j;xE9?I>gv zuqh0SELBn@QEW(^isU^04v}TSuk8;qcZ<^o5ybGjj>hd^IbsGIjWKr!YbdhTB6~nA zGTfPi5)IZOmo^a%?_(l&!rL8{%t*bGGO47BgL5{4;1p1Ksnfx&>AedWsi@OnM5==1 z;T?|17{ju9TE|EAS>`Pc6kyy+wex8!N{NyT#4ga_R(C9FA|zLBv=Btw>D%`CA38>} zSMH^uh0R6*h-#yK1U*Rf0+wq+N6`inrGlZ_wFJoM$A&+4+>VdtmQ?P55A1}Bt(X!Z z)qX<@{t0=|IYc-c*;9Y&kdKZ=wz2E9E5*o*E%PVbe!aEVDY*8b4N#teaCBE}rB0Lg z&mD3m_M+C4Nr;Lo1~^TgfSk0fnlyR;g7}=goRI2yH*1x>)6p2CM8aULGV$mea^*Y@ zOO>7Aoryy$mHj2DiPesCOr5?~5eR?f_+<7^G%UbVP!%OM#rAj z;cB0xqzcS^5zBs&!_->%CKeYi!#@yT0ytQx%kYm5JkuMMQXkwKmJ3aFrXotF*PB9T z;4qRTz5EkFWtHDU*1avU|Lm|c*1yhD>`>ZXru-NM$sk+i@2c&ye<329nHfRoiGKK3 zhn5LpRBt-4d1&H9Hgk(8yA1zEIF7v-NQ=9y;(PGt9j&I*5ASv?7Oy<^EH(!**qhZZ zzXFT|7*tPjbI;Jr@E-D{XAQf(i;72btHFC6r!lPH__&g($r9O9DqHU}_;(^wNwc+kS{pX>K@)f>ce3|00nG zLp}_;vcCtrF0uHaW0Bd(G!=v*7&s+j1po&`iaT*@=&UeeqaP0xlf_KB!R*`}$)JJ7Yv9F#|as={JJ_Hbwr2WVkMK@mWn{;NuQ{ z3@so6^xYe>D(The`(L8sAM5WT8GIY(r12lrea9W`pK#D)gjh{VoCO0ib)XwUMdSZS zgQjxIBwIm{VgmzpXDwWXU(_>CkK^yIFd0pZ@~}@Z22H5=l_%0iR8#;_i(sJN58Sg_3@CRrIaQ|T2wjw09L%AOgl15{EVyzCIm@yn!a?&~;= zu>cM^-x*a`Q{mjtATM+-!U9W^{Qd`kL|XA`Jc-tnChv5c08|s~0YsJrNEp1xzfaH) zbkJiAai|6kYHf0SsLKNbkf?ZgHcEm)MD82*GSpoO$5!)KBc z2cG)#txNq4?3u2IhdLe^RnHBRKC<=?A3YRzZJV-^%^zi3dFC>F7Qs0XswIg5>&xL` z4m~pv(xdewndwWcoRBBVXDU^RhSL>0DTO5-P9|dbFb9gNIZeSwI4)zXJd!;{A#qrG znX<@nXHk&sgfTSm)uch&d!^UgG9T!XjzC5Ms}ID76}cux+W7>2g9L~Nf!iVVT~PbLUVFE@dI9B8c%n8u#!(m} zZ%-eO(3L1TGQ7ag^tZXkhOGhnxWjPsmX--YH6cc^B;fm4a$>+&Lia6B@lZHQ$MEYB zi~r!HsN_f%mhJ;2Eis9V3RbcYk0UO90R(kAmK~KeE$d$vDiV{jym8nKw{1V0*S0^DoL+pxQ3)SSxBnp zmt5u}YjYcx5h>;VFdWf+a^1kKAx1Jk)q~s<- zB$5*gZbcQRkT=Er+5G}`XMufb-o=dC2joEWD3u=y*Etdy)1(TPq{sEm(?@yfDI9+- zuy(-U4=n=H8q`}K!y$(@RuF0+G^4`A4oWvj9wrhUFL5?n2#KM)5fh|YVe>Cs@8B2k z_akP$%{z<9U}D#@6Eh%UJuK57S&STLp2tav8V2OaE?C{L41lAKRc0I*D?F@CpQM=2 zcZ~8m%+@U}}-4X+!n8mOhA|Ir{VOJhC@#XYDU#n8YFQcAs zR7H3ui97;CxDvJybSO!)CFjV+Vho?-2xTf`$!a>JwB-=7vIgO*EP*R3IMgj5BRZwL z;4!U(pX*p;%u^dH^`TjpCBpB3@M_(A7BQ)OkfQ_r7mho$!}!&R*{_|T&uJg%&obgw zou;rmDiIKfbGnDiW7psW^uq~<#ieQlmc3aoj{hV?x>k!yb%{VB!IcrL4`w9lLNi+VRL}6C3R~02n1{8w?RE=&^7vFt-K7Tz+PAxrMbl*k6d?qu95k2QV59gb_p9ZfBy zf^>`wl`6B=Dg?p|d5NT8ZMbqUI<{*8dl z)IiGc9Ab04^rd8@ zRMf;EwW~qRcE{78G#wY#9ka~-?~sErBjq;7`fN|8Q?Z;blGz|Lx&SGLE4MPBn)9Y3 zlvy5fA>k-aGJ|lAnw6EMjolRJpDT|tbFbW}20EK%XWK%2)xgmHA> zMV)MEfHRVAE7|EqyI5S-3+)q(gQM5K z+}had#`;wKaHm7dObgXZX=B()lJU8?x5Hyq1(IjFDAlWZg6-ngGczc;VDD?br*7+n zFL4Yq?`u!icZuvfl_o*=v)IeJrZ3(jZWgdK#V;j3-E`VuI9IqE!k0PdF;>uIz-enI zS=P`mAPSdiJ>s*vwa4=8FLXeeU1&47phgs;E=W9*nH`a8RfS(fMEuiekNRzB3@9EH zMg4LIoN*CH1$vqi1!+>8M$N28T_CmoUrZj!8D6KY{R;hn*q!G6X_b%abV_{pb%lJ~q?YWRM!sN6mHY7FmlYu

    H{BU&+_xaFVKH=HtH1@xS75lBabz)dk6%l@k+UKg`69 zv&zMOIpOIj6XBF8kJ0wA?BY=+b| zhtFC#n}G@|_=M)g%;|?$J8GG%1#8JDOPg|(U`bcT(T~;5Vk)8G*p^o1M%u#~PG-J_ z^kiF()>@jy;cFeKF}l~CEojJ-1>j`N@W+dP9bsvu$NC4K z%RF}t&?b0`FLoqx8KWv{(V@49mqTDIpg2B?w7qX2KYC$IDwR^^97XciDUAM&j^s)F z`4zO;K+U4zqQ%CWnxC6t4fOc(E!z@?&hav79F z-0*sbo>~2^1rSfErTcn`VqVQBn1V3a663WK-%b|zhuyD$9Wp4&%hfGSZ*WA$2>tO; z-0mu9>6jQIRnV3M4c_PF{c2o(2f1)}kV4=cArxs#=XW|LV<y^QG(1CXgW*C2PXn>D1M!jXB_V40n2TaQ&zl^PjLxuuIwT)uXolqX5t3se zC1*$rVv>aKcc__Ah+5@IM2y6y&n8k-(X>@5FQg-Ygn|!bk=B`LNU`&Fcx82XvtyD` zRioA!FH@3cQMg>z3b9=TYS6U$K~j4-8YnHgSOZ(kEYJ+V@Rsq(S?8n#g%L9SGWC0X0rAqFn`;YS^p zj8kJx;d5I}mW+lNBxe|>9T+h~$p|bZKSu0(gCvSv+j5nVOwOSqMtzX8igd(^A4uJK32D zUwMav$I(=pyv|7xT)hpN@n;CiksaEXbb4q6IV}c1>sXw+@*CFW=$noZF2IZJOOxW` zEJ(n-S{8ne)RI2fVU~U${?+y_R04KXf8G&0fIjdtrBuKf2}SW&b6uQb>i5>Ud`Hwq zseoTFf)=nx_DK&1-t{DO_(exB6H~OYVS=>P>{COmSTPz}1y(E|UWQ*H7jc4hvzmL0 zyWy>l!WhPlMgp*7hv$_>{Tua$HM9|JE$rnHino(vJiU!PSfdoiSNLTIp9!2*BX}Ub z0ZF3wET^|#qx4q@$CzCVs-|K4s}4G|mtc(_)>m&n8Y8DpoIuQJu(%qazeaGH4)HiJ z4eQ-DvRh*1hF^Ca#;{<995QxNg~~FJR(hAKdMCd@D)yPA$*P`bqm+BtjS361xs=M!Gdb{7tblG zZPj65{tk)JtfDE-*yaX;Wnn-3uA`ILRZ#;+o{ux5Axf%nPVy_1U03O1Q}p+CSs<6VwUw1&4k7Gvr9fteDei9>h-IY`Jph+kowv?^))`$VU?XO2v(f1#`Q zSii&Z$e4RJR7{9AiG4~UrB#-qd~t>}N(AyqL&mDU-tKNO3llXa$cvj^Wr;g=_8F@T zf9MDu#jmfhz~X7;Qi%~GWx2e76hIM+G7-dL_IXmW&|ll#9h^qk*bjf~P{)|LCP$&| z6P(N>RY_EzQ6qvREHlO0n}u!!#tt0+p8fu;!Bb@I-TZoc&Ee77>v~sj7T~<8B#eI zvShGH&EU8=@qy4?k>s1=+7;ZgEEO$Laqut6gA1mHE+uf(4}ayjjInH}MT&mbW~hsk z#es#z5v^**hrsHuNr0Wty#QM>-sSK!!(FuzA6DR+7fvw#Gl~(R5bdamn32OAIE2sCZ!Ka z)7hvCl?gJ%qX3f?QW^eM`MhYycw<=lqq9{t5#*#{0kW{m6A=d z4J(sF3q>Owct$CvHW=k#C8>flM@tq(xHx3df&WH)Ig!+FAx6eh+u_{~{K%DuLM>Z3 zN|9zo9E=iUXi^hF-a|wxB@R=>Mf>5s4lmQvmFYUXTAayDx3)3$i?PYA9-Qg;TV$wU zg0ztf5&oTIXsKuxSnB-uIZ7Elsk%X**SXM?CF18gh}LITm~dqWBg83okG;| z{SG%1TrmBRLK+I*6lmMP|4BTmq-wE@NkZWR4sr}L#DplKeM)gW>D}d&g!Es;=0-Ql zvusN>n(#q~nOXj-9v?8ll01>VVA4_Vfr#u?9%7Bh6zJuD$iYtIPe$mt3U>HFYf2Wd zSza5DF{McuW%w{zaB3r4d>fis$6WY`BQe%!A9(kMOlk1hG^jsHV6JwsL;INKJggBu z=3p~TZX>Jqxb}4Ii%Ov`R3K&eA3`(4fn6co8v)b5-`hg?Jx#2SI~uo*?gFD>@oouf z+R{HlzE}a%g1s1_t4a62Bq!z&&lVgxax{FxvB_vU%j>{_UBR25cSu+KHSZL9^`eeSG$kr z5{?|X{uX$B@ea(EMVG5O+IJ@dMhsB!hi+LK1@~}7GLE2)0=xXmiIOFiWxT8Rz9&)H z;#NLS(&WOu9A?JtGt8m2@-*p=V|?j$cC#!m(FB&?mEqoGz_?`xMg78k9B^hWskF{u zY>~2LQDs1iAF9|QN<9#fo(3vk@g!7b#@yGTk6~r+cCqEHGv136jOBFjB5JzbY4?`>n9O5?zuPL#PQuX*}5}&cBnD3Oe`E*wmE20hZz$e2EoX~fiNe`nB8$>&B(2xg{|&RRaJ6RDCSW0m^xG=3S|29+SJX_!FV?O-WF z{k$p};4uz)oPjEW&|gYms9bSyC*=$C40NkT`j|JM@3I5Y~^kNfeIK7~2^` z=8hLDgBRJF5z7)q9%pRm!ykP*2QcH{sM92QEB)|z$L2Vgj~K#(R?-NeqB|I_;U*`B zG!dhl$gPbhkdq|Gwx5si3Cp)U(Xq&=_4W4i>nXYTs4~PWj7#-N-kJe>X=}fj=wCo= z6nW4%J0>StpG0)nZIb0g4UE4_3iip4N5+1)2~7*OQ8~}alwmumIMpb*hAgP!<0z3U zAL%b&>llo&qz@S#CQjDvg`NbB(DF|q>Z5>)(W5zn&}oRXBWh7u@lSOO#z^s^fYrFd zWJJrR7sjYTPbqTMDo-Q7M}l8+JGqIm9i<-2b6jmX%1+>{D9#1PCZHL3mClw#_A+ z(12UGj*5wJOZ(xd!#|F{8=+iAH;xl3v*s*-P=dvP%5cnRU^=!g?rrTL2DH+JU(VXR zH#iy@JHdtwXEnF$o-jn7ye`tO3WtMA6=cC!_|D$eRw@PZbO)b__ZfUlO>qfWb*T~q zI1L!_%sK&ODhSR|$`c;YbuB%=g`M<%xY<$2v_MVEAJZlnlqYkPUh&ZzZ@k5BcS(om zF)E%xF0`2>)m7uih}7YBpm59hR7RyA)#arVQuvZilYrcUd-D1iQ9KeAo=GnBU+@>| zEq;!paK+65*n3P`)#flUavC`L5zS4B>OAWIBQ~Qo>(zB{;d34Q7!EQX$IwvxnkW%{ za(SWBpwA*8*H%tP)N@CO^tgk|tSD&`(oDb+_~!K(B2FwHT4D03ac|iKv1$3Fy-PYg zC|BHHrFpm?PB{y#9eRcaJDW{cSiO?+ri`}kRWtb!zHa%Mc10$fibC_}rGI4^` z7DMudRhk@(WK+y=PbQvUU((;nff>}TAc>kMg*}-LF8i)dj)aqr(KrUGjACt(Xg&tiN;_-u!oaaT+qQXMlbwh<;AkSt?!npL`@Qmp31ZKQ*Lh}!J7<#Y+Jh2pkp2RDq) zI!4Fwha=W0W3;<3lC&3w3DpcA8o!9!%@GIZ)irNj4beGLs^Tg~ZwjX!jZAmcv~(k4 zdGw}p*MYo7ERWuFi;PX~lf8nA~^`NC1kEM(SGLsEf~JW-X#1;9%L zruvloZ{%9sWrvtqENYz+3*96!q8H`z9BFwywVX=$ogpm!dk#8WtbkPvsd>pOxx-Ny z!+>bi@Ea;sW&uvyanaI8!8>|NQ%UP&>1G#lM%u_pl1!XPqcDfpSu3 z5_#@g=%ZK?ELpfM(Et@K$b@qwUQmxx7LG>7-cE+-;o;jnCQ|_7jrSM>pHED>X4@U? zuHqs_D0kW4{{jb{iT2pOAqD80J7F@q=LA5P4K0@h-6^He-D`VA7ciA$csUA10`KHjtEKY!` z69l3++>Wv5Vb`s!IRaz2n~k}bk$tWJw#B{W6vNPKS30E05I7E_!sQF=j?p3f>I%)D zGPzWQZ5(e$1XWrX#cA~k3t;yHS8$lU${i9tLJwM{bAku(drH5qmsiA=h%Et1Xb7Lz1K z!3>RC)Pp2j4e&KlUIwH4Uxvy$MbwJg=7>*)bCaas! zM{OlNpS-EpG5U~9i?@ooYQeD_XII5UC`Ttz@`sTBS&P#YtJl15NE3kD4Pu~uzm%9X{7@K@eb3tX;maIo#sIcg zbs1w6(?}UZj1@=GFav@40%CGn;$PbKT1DV)CGua`Z+_d8xGY62~AjG6ubrC`3;2o$g$^jv5OkmO5+KNeeB) zOvQ)FaQX`3Gt#)dX_bG{#CWMAl5rDkv}|wUr>GMK1j^7DI5F~-WWZ^ucUPFl6kg`g z$B3p354ASsijlM=7i~mmsSGbC1xd1p(=0cK^}{P1d}bV6(P37R;-$$oWV#z}=Q1#H zUP%HBHgmO(iE#b!Dn}us6jep=Y3LVi|GFrV%{9N$4_{^PjJr+|SmM@M_-Y53Sv@N) zJeUDfNfZS&kpQYp7`*e>kN~4fvUtdWWYdkWc04kUVH$W`<0vE!KKp2cS&-)VEl)aE z&F~tspv7fX$->t<@QjYsR*z3Au!#|wld*Uj>O~mLj#T$Xx#_QWFq!B_)z(n`sSu^& znLNQe9fhO*1MxVmQ+YzDsJLnUjSe{zf*7UY2BivEsznIRV-7GEH4kbkQqkjXQ%H?LK9Xvj)CCehDF#9B5@5F+G-k~quqZR9}J z#*I+av`3GI*E<3kgQp7rG!K_l(lh`d!jbJ}wQqD8LUjkii*nyb)y|Ei+~43R99+3K zW`};;m4_LX93lao&Y_w(ZHL+yDqn{Cxdk8<(R?k#50VYNKFc9UE~O<5g||3X z8PC+(WN0eEfMnT5J*!pp;PN5oIC`^|IfQ~uKSX}i2r(JU*8CrKq{f&aD#3=Uq>M#r z0-!lv)d2kwBFj>b#44Vb4?pTK#|W-4DT~hZ?%Iz!1ZVo^0 za6c&vKMIkcuj~ySyP4VD($ZB(locaWwWFUP0nx&n9c1~Z(~Uprc#P5JeUYGVuRohK zdBbTfJ&wW+gfxq`uP1H#;inG(Sgz5MjUK-I7^MlI9@v3;{22m17L8n=C7egHZ&TZW z`B}%|Ie6v@s(;KmIRs6j5zAm9`$cvC{O8D*7MhM?Of+jqlyPtrk6)Q$l41js)1fX@ zMt{$Y>{EsalyN zkPdgvK&{i>M&ePU`qEn+o3R?C%3~WURNS#8f%C~ zd)g*WnjlP^InQ^kwA8NrvK&FH&?2oKS0rC(~d8**vCT?l# zqA|+w8|1|;tbL5|weXvcO2*2mnq|;w6=6DEv2w|$%3UqPZxNJMBx8)WX8pE<&KMW! zD)M1{|C$(eovMiCyq!<}9mAA|qxbN;4l`r9DrU`hsL9b=OJsNOudQ+O3(9xKjIXqv6-?!IB(p#E&?{JuzdHU4AAWsGK*LA^?C>c0tIHmVBkQuCBHuW87YYF!Gve60<2BeCx7lZjA6dAPkbpptU^w*WOp$M zY$E+i;_8wzfGQ2-B%5>0LhGPM-szZRS|crzqmpVUQ1(NX@B>OQ5R84W+v|5P;|9vG z(UDu}P>;c(W+F#szKal@4g>O}nP(|q65XoM^k0*L&I%MI!QQQ1xE9{!7-Zht7z}kF zOrW%CbxGUb5SSByMnpW>h5$qOTL+tY@zmS{`Pr2`35&!tauAQo3&drHpSe!Bvx<8Q zHv0SF?;V3NvL1)NxECzfF`nvOLZ*7BDt2p&U?1txtGx}B=#-MT|3I2ds=$y5|L7QH zT$pP08!!qWNsM)jz1oJ^KM@H3YI>k5nG^omA&+4K3|9q}OaZI3LG_C={0q5opCr9S z_*X|D6G5!PSUk~z7#XDKbV%Z4vhi#OHx5C>s1L|?{+LQR+-I( zp~qF5VrBSG3R0z)-$N=qQUU$2&WoS8Q-Hgi@xw}IvwgAK3*o(v&KNl^&`2E$(FPeU zTMRV&HL``-P(}bBPeckR)Vql^ZTN zZNu(%KfK>zX7)6yQ9_@w5O9A>Xf^&Uhgy8yPHysHdba)w~skW0?OG2fT>Kyq^xY>`( zqucGb>@w7IAOog19ep|y&idg)4!?z8jc~OG@hL%;pNZ8AJH1O=owW@Kuc4VgOdQFK z@9pXd%J2~fl?f=PDSx=cwMIMud7d#FoJ8CyEzDqYMI$ZSCuHf^-<9E`B*6%W#=2V) zvjTIn4sYe+l>#4tR`B4G~~kxF$=aFEXN4q5dCHX^YS#fa_ScFC%^j zYT+tOw=r{BlTo0L#wq0l3c6-f7t;b!hED^AtPjy(Nr~0{a5o2^*(NrXW>$~l4~P^W zbmAf^z)9uuT1NBTNkeur5T&;szlS4mMIW>t;!k2^AWuSU)#Udi8YlDa{%$v{hI=`n z%+RV7>5yCDMVj;_NB1F>F84K{AOkU(Gka%uSJUunfxG)S0-1eFYw9FM+d6%$q!>D1x*+3{QH_Sw#5 zq=Ie1erRv)v+hm!3?kdgg>oe~hX*<6PkQB|6iJke1z!*&U+i3zip?kX)^XUdRxjeg zgufas9P>x4Gyu~HG#xNJ#PONMUyoSHtj#SM1yK`RNTQuT5~Lj7eOk#Amna2D&@-P!T(&i@xqS6dk z6P}Av$}NZ~0^yMkJ!9bJatorksFc+uVIeD2WFRz6>(pm4spHWOc?_4lnJ4T73P>6W zmdx?lgy-VVVMAjGWy0W?KgNNNGY&?@L6TIdm^f(|Maq^Eze8`=UFOD686HbkoWJX- zRsgSIS*x8iFC4>D`0Fdo-~Qf8%$e1(I#Rem*UA)}VOjWzu(8L@V92V<;V9J1a zyknGUGaIO;QR11RXsgzxic)8=JY_#Tf#6)lbvX@Bbg-HAtJ3L%(Q=ih)-hIb{aBBe zKZ&>naAl-$iD|)KL=2nfdT|a(Zh2>#%>SqD%LC)Os`L4=7iig9AcSSuLx|+qPU6ID zmL)lMV%dr$$7U&JB#o`X+Hz+UTY<9gJCwChO4&-;_pLxFrIfOjQr5B-D5Wi>Y=xHf z_kHKwbKiSsX5L(tA7yTd<_0SECWx4vz?SZgG)-vd3m{M3wx*uB=rU>6of5ls7Vu2VHLyv%HPs4+M^jd+vB79{s4tWFb94vr5Zo|}CTDIq9>3x2LSVG-bJ zi}Re0EaQ}4_s1&|q;$<_c;J|V&>#;4sqX-4=k<^)J86jF{sq~X?1T%Pq(j5&%zJzVI7)wr#TL4TlgqyQG4J+xDW2e~3h zUTQ8EhMkT&uet2df{2c+3*{C>G30l^j@Q#TcH9uX95y=qQfnJ>H#iIh3<+FFAzcLJ zu-EJSgzk%d8#x&g?&WmV^!k#YChF>elL}$bt6Hl&IJcofdAvQ${pK7#Zn)(Q&GxPr)4cVeMp^ znkJm6oK1`?kcy_YJ&ynSFjB%48*B!9IR|YYf07E=C2^Yu^CzIl!X8IlvyE@F&Ojw_C!xkIYp;npy?lY2J~~`+j>cdn-b|&VpIvNsDK&AGB5r(yG(qVCGDA2mH7-gG zA%M|UILj(nGF337i-nEgM&ftF6nVL6jS-RuqHx%Lp{uiTIN-=@Hm&PUK=mR^9H4m) zVAar*M)G(n5DN5{XTe@ONP&!;VGvL!Ogl|A1yW24J$r|OC8%RWMaBoR&?>ZqCL4%J z=URvf%8KD=#<6EC$@&aONdM3WTsG|BIkjI^?#7*^KCZ{uSE7Tm6Xu+poX(=7z3my4 z&}0rQ4&5IjBdtE$&EeXa8;uyhk@#AAn4~4R+=<9=Ga00gNA@&;K*|McYT=eV*wUjl zVZmXlq>m}Nq@^VVcJH!>y=JzuK0Lt1EqF2()Af6}8F=Y;hhYb3vB(fX0raaNP>yHM zi%9nSI|((jwMjslf>PXF1x`2+cqbng!}J44&tb#j&2hE{>(d81?wW>S+z~*lq=F{X zW_V%&c;Obu_PKReUJjf}?sDM5_CEEp}Rr z(UIWw2j|nK>7%Dd6nN71SnrrPaLy5S8kw+p*j+-lU~1s}h0!Z*ZOl6XHI8l_u=!;z z^b(A8bu_Wk*2aRd;cP7b5(9Mzi}`F;&!w}m1|xGJ+0@x!YZ%1VBGQz!XW%8v%jGM0 zy<)OQjyVyt`0F8ls?4Qwg-4qCWeoHzn*VXCwc9ts= zD+Qe5W=8&HC+O1Qb>e-8b@)ektP^vzMdCGAQ@+ZEY2cPnlff38;ITG6jKHL|lXza? z8_2>qWe{FHnhjwr ze}~N4vhqA13Ao67x1&cTqW0*~yEQbfqZ>M;#y?5*)3K-zUOn7q>ddYaQWJt=BTFUS zPY5mY))%HtL%8H7NKI|aqi4UeN9R*d)=*23eRikitf*@)7vko^j+ zOAAG@M2SoPMG zN_MuvNRyZXW($r!Tu!ioWu%oMa!ZgnHPd6^nT|83nbO4Q$(!3gCiYGH7;eohMviBZ zj(%nh2!LTU!V6GNz}NR|$6WKa^Bc!w_4mL?pwJ=7We)IUhIKj{EqFbJ2{|UHg0TUZ zUsl>E@)#%^p5ruRtREvp?4MOU^Ep13e6;pfa6IEwnn0iD*lNn!>Q?|_Z!BX8`V>DY z+SK#O%Cg24Wt}CsdAXA(87jjI9COWk>Z}m#B(^)-SZzN0fl9{y3K) zy@V4{GgaB^M*x*kL6hpF)ydY@(W`WjSAxuRymAU)mDp1CK3Gc5=Xxa!Ujx4r6~XnOpV3Z#HygWPUJmplgffj62{LRdYr#U{2XnV z5MJu|YiivJJVIE#SMc;yv0`__ACndTt|8mZlE(*bJIgj2Ugo%KOzP5Fi&-*geZ>k# zyK8ymBWHs%<}rnf#8Pa@R@Y?8vQZlGUQVIxjLr3S={lKLIDzL6t{m+Wuuj983acQg zq2?BX-SA4%(msinxs5rU@G8fgF$q?zdk-is)#&nvA@V0A=AH_t%0)3_!>b)-jjv*0 zZ4_|gJm9P=hVodzts$qPpR=6w8@dFFO_gM|hnRSTk@~&#A_Y zmB7RfN;b-z24=mUtTd1q)D>Dt0?3PFJK+tEco+U;z>rax^TpC3&XQG7Ih`^Qll@6Q zL9bG854T|?8=!dM-bhj0541)9wjCpuwJE&GDXVF<_H|q|7`KJ(lMuq+i;+ogz45VQ9qyY^l}Z`L^&5r=Vs> zwx(@VFr~IJh!!joSBrvpCp8QT$Ke=Z;W+Pds%D^jK#R3<$qmOT(YSCN`%Mv!^KR<3 ztt$-^!9epKC$7fiNUcZWlTuaV&DI&cvse)$H0MK(wx&bZ?R=LpkDLb*W;w^W z7C%SA0!(@ut*c4)*RZm7QjNiC?6D?{Cw3Lkdr?u1_r=-B!V9phv!O*>e} zF~j~fftk-1mr%6AM;vTTmn>Q(C$u$eS|9CnSL`Gj(PRMSDget)E;3@4slOp3yQ3`` zmfI`ns+{UN;iFDKO{rUV?7IvpVahx2FF3m4V^qM#Mvv5pm`OfVNCx7MX{>_7p{23sp|ok(xI(SI&n2-yA@6Z z)7l@1EK7xPJv!yr3_u^~gCz&3^*S{()t-0L3N`B~uzb6wnV7jnHF?EK| zII_{^5W23Uy>6;h^!AqMur&TGIydIK1*trEzT9uA)qni;d4$v&BhDo zT3M8BNk6HQ3Zjm|%3)rZvZIW-ky&9Lv%C?Sebuv>BkjZN?ChOdwt|7>hTe)v-A)bLfupRx7SZ*;7pO3V|w zM#|92Nr>*c_*MGPzeZhLwu+_RT$#r`YF~F^YKF?feCy|&ToydF`sGI?kg%NKoNB)6a+7#T-h(s zSIi5jKclhYlWzDoisQ(k4hFd^QA0Yycb&eBWkx@rMF}$bSa}0uG-i>*f)dzKWns%? z_MPxO$6aI8S+x}3)&^WWOE;a?`?4B)xOx_nZuk!})4O|eiC(1dJJK4bR%(M=`dN|! zC-x#uNqH(;lRqFWJwzOt?C{eM9eGVdtZxkwP$sB&>IsR4a92+o--E&04L>43CrwM& zzIGBZ{6BUAYC=bJ@u1(1?vOH+9?X%v@0DxH_8vSuhoocwNqYQ~wF|a=xY>w3LL0e$ z;&fz;T&b$H=DAMk!Bu-P{zms(Qw#hl6>)fAh0G&6p;yD}{~R4Zo%ot`d(U z`vHzwVG=5w^w+>-T@LN7QDY+-VN^;VKpC`?6Pi;o`H(;ZJkq%rj<#Af`VER;Z&;gW{z$}i z$1ve=11BJ(7T_OQTTp%vC)Vh}$k7cqBrQvy8(EkeWxQ<38GuniBwX!U$5vEg)m!P07!3*dpGeYcAZ(NvJ7nYw3L>=p&wR zpqDYiv~Z2zob0y-yWJ2!f*)X6j1+ku!*4qw7vs-|3^;}sTb$iD--9h9-$7w)6pToq zL0L3q6c;Z~0P{NY96lgKDiv}2K=a0Q`T$b6t5cf%QEWv@4>>zl~vk7)34YsX#FBnQ8^ zp&dC36w?uUXJbqQwdj_D77hArjFA@Sl(4iold3o0! z!%8cq52iF$1d+tR^EvW#!)>X8d&fnfI7TSkQ?{VNh~ailNk-6C0To+F%3o1|7T-Az zrGtwG!$D?GDMF|8)EJGw0xlldK%Nb%mSJo)G@QVzIgG9L4r6y93)_tyL*ms2j1LWW zbeuJIuZ<)9430e%_T`vd=~i(iVRKvAyWuWYMlr+-7AAXNdpX?INy@P3 z;#XCR2b4M0EIK60ATiCUc}b#_uBtlA(bhOObvos&f+f9@R>5SY7Lzo^4m_LoxsfY_ z5?C7&bfxLEWXt1hr=ey%wdPSyNb2AuYWHGNm(M zGKMP1kHnE#4AxX}Fj7Kmka>cXSVG104?HV|0UYHbyE@@KM_+S@wQh6MHs34YGCJ+o z8x-kEwm)i=6(B(c6>_}fJpyu`H1^?effJW8UK)nBLVL0WqttdB43KGp#4;?#04Ozz zI^jaco6-3DdiNuq*tF5K+Oym|j`{N}lV z>N4$w`#9nYh7-&8wGot|WOaAhMhjubIx?d!?n_QuxTUklu+6#1-sOlhoV5m`-1fwU zyFltvzyAj77=>_ugPX4KGIYak$A7`_7f&0uD!`yD=6RePod4n-pH{>Zj;Uto)%h=e zUsO zw}t8dJMG*0w~B53v?EOh)pEmSktwLx*0}>0W}Ld5sk8XHHro=OjLQ?nAHcnjt&MJ& zB{$cf(S>KDUh)jiIUO~_iS?a6oQgT|g15>w0|hp2`VC3Ybf+s$yfBd^((Hu9Af zeRoBW1-`^E3Seo1JWMLt_FSTIlirtO?rA#0-7$B4G(h2)6OQ6N?`P!Lr|2RzQjDAl z_jlwqz8LdGw&T&cDw3pC+gAZU2iY}{QZ7>ICD5u1&ENqP#DTnsYSint!vme9nyr&M zyVm0hnVGaap*xR%NPR&acY=;I;_~7U&+H8Bbu8wJlKh=v3QCJP>z2nfGU&^BBZQ_x#dM~jqJ*i zFW&8k^$TT4!%{7#s6I(7^$q)PoM|3Vo{J^J!VV?T!yG@J#p;vWw!>-@{u zCwg4f2w!ycHO*k29&9&S`@`afgZ#tAHFrKARKeT zE*o4fCaf1NR+5|`?#Ch`^n^y`RBu{29j8(bcyjwdCoDNtHHQRERqR} zaV~jIGK^P9&5nS*l4iPdB&<5_8eemI*G+*?{t8-k{kulSGr(x=aD?9Kxb1+%GVqA3 zJN7;J>#H|bd1zS(9R?o^%~rIEIy}~ZD^{?8_?K>Vs;Y7^Ko&-)>9X~0i+YR#4 zTZE6BvWpe2beuKAqP2$f{)ww-Zh|(kz><&-KR< zPa5H@Vt2zPSviHv&53M(=KZslHW zC>d&}G>=spfgVBD+W|9;2Nn=wTanrbAL(RVI#`AkiXo~Ld&2r(15PUVGBV6s=nnpt z>m_0ChDT8%>q-ObDlY3sJ6ScGUnZ-%QQV6uowDk)ehd}R0FObjvh#)n8;^DD8G}>5 zh};M#o1uDMzS&S~ra@O3HUJ+-0h|!wZ&;4WU?14 zr63oE3l94|(XrL6t$^FYv9*QP;H!!ZR_sK^12DkCV$)AV15Q%USabEjFg)Q-;?uqcjcHxZZpU*}2v&-)H+&Cn2jG`d=?nf|YV8 z-)D<1(y#;D-S9Lj;dp7OwbJEWPj_;5;g1H))kU>%cEHGBdB;5H5n6IQsKic)6H0M} zlH;i@`155Kf#G)cMeC@~piFL4cb4$RmKSIwAaPzNJku%77}*6ztF8~CjFr;}*k+Z@ zkfR%(MFsfB=ww*^a+ZYW3T!Zawi9v5;Nr63!h-A85olYERqg{X%!sL*Br{qVn2U-1 z_bH8C3SMF4JwYhNbDWr(T_Eki_DwAkdlJ_12x@$d{mo4d9M2^yL#a}D2ZM^Vdv?O} zoPrulFMSI~O;UKi3h4(eoMUz)X(N3bb@Y5n;yj0NnKdqnMwqfPyufLxaYkF!ln;AU zz|8UeLQ=5@GtL7Wf($tdf8dB}8e)>&`_d)E-e`aqk@uG1#m*y=tus@jB!y4y@WoC; z#!?dp0`T73w8#hGN>hMY3r^bvwg!P*7!)P@kZ{6_dmy~T$*7q^lK;Io*Ro*A^f*b! zM?8OPzv@g6MMqmky2!uDB5CkHx2r#D>fm6eK}K zOQ|ki<|NcC^sM1kFW-rSi{MV}EeibQB%|GeMo)F&2>(fn6CbqDbG1Ew~s7xORR%?I6H#i&1{hz1us zDDEp+Md($mO619)LXI4WoyAlp?xye>r>JJYR{xZIS&ONJBRyiKbsRHkC>?fc#GwAy zl3F4Zmf$EwD$mzB+L~UPjsf}ufnCLt31|*KH});S`Sg0DqD|e|M2-tbRr7{c=JBig zmhnLx3}QmljSa67AU0J~% zEEaQIL{Pzj7Ed5B*+@6MncTGHwe#R`rslhRi<6OI%SQy2QiYQ>b?k?;Dfil26E`dX zn650`V<0-wowMesxP>fmmvvV4lZs8Y}6bWeZa{hBp z(DVknWDLI92XE_)gIpA6xKv&6_chqA55vSh{IJc`rC%!R}DX(fK8+qDk5_Qd3mM^Nx=~)^GYk|}&@*KSmL$kM zMAUMa6nhH1W#SuyfdLtus=DEQ)ItBK26G@+P{4xl{Z3BJ%DdP!!0eHt1GU?fF{MQG z`nF|T43ez9x`vS*H|qR3m2gznC5Z&>h7UL)HM7{j;jx5wgpOs-V(KZmTc@FYsWB%v zo3fCqn^h?e6?rU7A16iRHpI%Z6F%tl)fl#EmW`+XwTMb!GH}g61I}#ED1JBmC0QBm zC6f+v7Ou7tvuqBq@FB-vQ&D|(Rr+GeT67FIA4xjW=(|Ij3JT%Og|j}AjQzuodXyq@ zpIl8^+EUg;LP$7SHDh8rEd;;uinLMWu^=-C3K<~8M#0K8e8ll*jp>Vm5sRK)QiGGX z7Tboa;^aa58*@ zvJ#q{?1dG--j?+{r`-Ku;+hr*>7eltE_cK&G$(N2LynH3t$l@>Xx77cn@1nRM~E`) zgs(bbHM6fe+1ReJ3{*)~Fj=@A5d2tEl?cPHQ35;JY74gsMlfo!)QU@w6y;i9zu+1NP_(ifyNX(xQgv1i4e_LPl76+3#r zGGV2+h%4FlxUW0Nt7p18)daArIGHA@uMTz`?64+*Nuegpun${jG4devn?%WTZl)d=l0i(^p(QXj9 zq+^+-za(u)Axj=rJY z$%`$_Q=4#SV!Fo7$Q#|Ibc6O!oQRApZWYh}KxEm($G~%Hb3$mxz#1>qE-LY-6o`ME zAefx&sI2o>7duCnoAbDz_P?CEjCNf)^c-QawGa0JU`GU2S}rCKNrz^?LNX4D;i3(5 zHO541(LZwEf5wBbWJBH zqqFE7r#Nxs?}IGHRE%uYbRXQ$o|3;r=rJ@P2?wR&Uy%nxb6})t>Do?R#@pD4CXZRfiK4kb!Un_>+>rt<6exda@(Zc155A=pk zxV}?bB+~`4~ZukwVh`t$#22By!*2YH84>xdfY6{Nez#SuS z+QRIq54h}!B~L_b*NyXc;=%IpIyZ7qI&G!i272c^&&!*Cu4l(ff>Tp&)%F8twu@!5(CILA>TDx)8$ zuwjOn(XpyvLxK>BDIeI3ez9;9rz68~uej9W1ClODCVb(TSX-FG=v)kzH?^YRnthcq zGcc>Ir-qw32^mGv;|TDeGBh6m6Nk(~$jvE)1}R!K7Pbu3h4YikTEy>BQLEjCX zT+M|g+%AD?!%F2=j=H89^lZxZ!4n?w3Bm1O;z4QA;7NSCKC)zuts;}p~wF0reZb3l4Hu_NaQj|zuhmtL4w*h1$F z)=A>rMk)}BVU3_HFhq1Z^UdN6^X;6TjCrwzuw5LY!q5;+7GKx5>Yalkdf1alpL5(EryYeRhm(-mdtRzvm>rq-`Kzm9Q>%<{V=7$9g0Ln zf!~EXIJwI~1Bw4hD(>o3WJFJ|_ncj*K+3Q;$paFT5?@pEpXK;# z`eQLwc91}D0mt|{@r0V8X{@Mh({Hjnz(dNb$~7A(|2(wkkv|CeJxmANUVC+;70z}# zYR08vwb{F4Zg^rv(>Gurl=m0zL3Y*$>(I4|bDWM0W6QUSDx&nXX=!>zix{B-w#;-1 zD^d`wFK-}+?M5ezIt?}E%RujNKVUJ>`(5-pevf-}!xn0iO+oA>99ti0^X9QmIM<2U z1=R!kXIkgUfgUt~^)+->?JnG)NT3oj>kj#hr35598;yO!EepX)GWxC5$elXa1!7Sa z-FchSnNe|-j?{xFJUH7m?QTHWP7NGBS6Y}5H`jRUY8%-x&vOEH3@#`g$n^VKJXI{| zq6Z@|vVV|KZC#1mVWe0ZKrV2!H6AS+#<)6ATG^}B&@%&+P!rj<)oj0&@U%3C?4TqT zf(13lSd$B#nwsIP=*G^4UxgIUKoM-h{@g_HS+H=Ei>Rc0Bqw@U!cHfpW<;@qsW@li z1A^V;oQ@j2`g5_)yeHXd-yv@#_KoAo+Iu9e#n8O-u zt!}tC*~Q6dDH2klj$pqE>+<_JB^fROTb^kPv8N&qT9KtVW-Kk;8*zw+EKrhG{OsEzptUo>)b8 z!hXj;JDlG^su1_#h~tss#>ohMBEWw=En##jvI)pZDA{2-tnss&YLTu9 zl*TNTa4?E~txlM88g>kR>%#c9Z|mFJlK@YiYBIzOT!+X-V@@)ZTk(X;9bt`;lxC7G zZhEdDTExs@@^OP;ll9Lq%D|Di>>jTv;DW0s05jo|$pjvketj~+!H4e~HrZ=GSS+b#?bbWG>scLNOLQfS!uT5Sm%teGcBGRyAsC(n7Wef=Xa@q?MJ@6b?XJ;K~BQe2&~f#!Tg^nR|9nrVNq&V+1?TUX`6H7@P=+g@72P$lP=jNtoB3m)aEKrQhj+?8^ z6@*^X0fZG$SadpSdfWh0aIuOg7okkFkJ+iT#%@IGBc5HNe01v!CJSyp$ALPEVuQiO zDA-`cpm)rvsquLfy`%r0u3-wn{z%Xb$H~co2YpHt0mzx$B}ZIi5nB^60Id&ulEc3; z%u8Clv><7dR~ICbb#(-tWc#_>!b2SKj=}Aq)Jt6gX2mKx%DG7QB>hCXW@9fba}@Up zO2BSmu>+=#-Y^xpuhz{*Qc=|^!JtQ%G+g|!d?M&_IIo6BLnZ)MVcik#xZ0(^^#}(y8K%xfQZqVK5PG9#xU_oupE-`p^gDqW zSCaT5Q3j>4XT}74wv!ct(^fM-Sz$y7ZIKR7=7u-{BSzI&V^ZogR(2h0MkC-Jh|gH* zVC4n(YyRtEP}-mfHpsMy)9^?x?0K~FN~a~m^K3|31okvi!Ig%m(UFk}i8CmL>m+Uo z;RZu)MVxZQ%H7K`ChlnR)zz zOGtPvSm@zlj<%-$hrM(OR%o~+jWkG)L2}NH86)<>&_} zOqz>!`V{I>HgxITrpg-1FqyYRQ!b`-bL`+$nQVj(2sa2a84Z4~iy zkD?}y3EgI(e>(NfM>{PUV?u<`R^jl3W3Cw(#8Pz2$0T;FNRYJv%Tb2CAU}pX>WRw0(EBB91Jrqn&e3JTbrsshQ+_vui+~ zMit!Gknj)8`LKs$uyc626H{Y{S}~M^NO}>4XdIs8g~o0=ipDizZ#O)HD!3q9Upomu z)-xUP4ymWUhnk83ue8F`DiAE8q_0n&8hYrC7d||Tl$>37oh+_=;7-%C9dC`rS*)$) z`+QW^0#26q<492(2X&C=QxIKit>t*LaSK;em43EP^8%;q ze#3RqK7y~e)fz1Us=Cq#{n(@cCsoB90E#jCh1AQ+Y~ye=T%njFFzBpy=(Ivk3@0+9 zGa(2)j+*@tkBou}Tjt%h1stmZNdr-^Ydo%p;|eJc0u#iiZ+F9ssFAbS3XU)`;Ks`E z#ZF#^UB@y6#At+ybz8-i0giW|#lZ+UGN^zH%+6B#7<)!|iKDLRbv3=+;G}+LBX;cX z+S&ey%odO;7D;$%K6Q2W)cr4gWjgf)PC9&H(Zp=*vM;88kL(!KfPdGBsWjO(BsUw+ z%F)()nNxHL{&v9BS2;?WHj-4+0C?$6g!Nrb+ja6*mg;zNZHTJ)0 z=(}+cKU7rVo6xv4#uQAb`7qYq6_u+(IilrIrkX_ju)yws2g5Oewqx& zc#S&FCKOk{hu1kF8Kaz{XmRu+itDPhpD*inSvqo%>u|qP7D;HNucxjCbfqPxtlm(1 zBQYsVjO7b&a4M$;7nijn!&II2G%|oe-9B79vhJFV$j|)^>0xiQBE(@XuE43$M&dU) zaW(!nH31F7t_`y10#gFc#uAkc#>~mdrPtn869;wQOikjBjMsL=c|W|x3CdXD^zCyI zPdFxZ*TIx@!&}MD;7eT4*nz9Gx!PJTB{6!N(@>K}%W6!4Mg_?R#Xiu|llH{i1>r7X*;NqOQ*ul>4f(>MKwcDF$VT58cK-b z1}j30N=6l$$@?hb%yKcAR5NEs&I|8%lJ?^72TbNe3aJ-dPw>X#!S>0@nv6bfsot&C!K6SVF-J-vFR5`O*bT^#7ODj+wNJo|rYT^p0(>%sg@knsx z0>(b%bnP2np=BJ^HV9p)XF)wK)INsnuc(e53)^$pwqrysk?mWev7$D0eA9H$U5ja}qU_=uBI6V7Fg zp5Nw|RZb72bi|pK8rcmTL~QVn(Xbgl^fy$(u>iRZbRO-T3LkYEYBo7_#9V2{bXO%5 zu_Z26R53eB&3UT1VCLAzC_wfx#7?#aclfx|kg=jlhd4CwJud#xTbN)|=Au@R`C(Q* zic9!z_yi@;mjM6-UGcPA_@tw+iIKKyNc6l`s(_Mu-k(m6q?O#?l9i(ggIBS!f+dKY zhUtV)IqsTQFZ?JGMaCm-2p(6API^#en+El-bV&X|B{W^^8$iXBwi!O{gw#0la)d-! z8Mmf4r}x<@J6v=teBJQ(Rwf+gQLZ)_bi!wxl$suD^${_&Fg&31CVrO0*F+Jlb;9Qy z)miv>z_gcI-7Hj18|Ca7+2gh$4xwWPkDkL{UthLW@~wcj2Y2hH*6Z;1Uh2BCun- znl4@a3MI*QtsJQw>0BWzw68i{HQm0XD@K^;PEUlAxrS4KB5$|G-VI+P^{rVe!nvLM zGpm|1JFQ~A?sQ}r>=8|y`(S8k511k&W3hzzN6Iq)&OFA<6X6?9MU88zup{V*SX)Ls z`bm{S3q|0L(CU|;WIDiGW5U6ecQ_Uq^Xch5I=Bi&EQ<{+WVpuKzlLiTy5XDD$B7~~ zM;04QjPNZdvSw{jarvmaDwyO8LE!**gG)_t%eg@H4;BGB|3ob`zjT#^6AfH%*%I{I zPEke#@SxRJ6x?KS<2k))Uq z`yu?RBgwE=?7K>1PjcS`BTQscv`>o{{Wof$d5KVLq%Oc#3u1mMnG3$_q?~S0)F5D4 z&%srEY7^To?S;O13;vzz&VagT1@Puz?32KpkN`9KCco$8W%&Oi*r+!3*kZLw_7X^B zn})6-owdlrye!cc+lJGC`)zs(PQVpu)w5e}%+ z%7r~8*-Gs+&RPpQF+OT;d#o9nI6(;wNW+B}iBVU$i0%i}%w8vnQ*cV4l7r=kPH@el z#{_qfYmzxwv|#(83f&n0rY8Z*kEn+B8y3Mb@r*nK?}IW7KXyuLQt74F+tS~i=&|jj zna*@rfwmfv6}deqh$BJtikFU{{=_NDu%6IHaEez;rUy`H_K45BF`iDkcEe98p-=b= z>T_vru@nBw>8P=6t&Rq`Jv96!;>x(F;V(Ujy;a5)0%wRQEOm$<|0GjCaKo(%896%l& zn~KFp-3`B{T$WX6ad72$HNSxJxWnrit zfZ344H62$?w6m22kRY|(m53xKH)9`?yg|n-A@mf6k&*pKH@JaiA<}$M1^cy~`8*19 zi7v-hxV95hGe{Q;v_VHn;eb$BnPq9ZPK_Pdw`X#8ZWM;I{jwXbLp?MUi{q2mbviB@ zTmfkZ$0q88A&s-q5GyeS9D{Ai=f zpVIrHo!yX9(Myn#`NZnl$yIZEr19=XPG!ajTnUO8fGdOkA?54|jrdK9k|9oxZ>A;a zZ#gYH2DchrX!jo9G%UBAzcCrrJP--S$Jl<;pX=G48G)5FBprhC4}F00y4bn zHk3ynS{y+8fJ+ZLFelf`>|Z;cJZ!&1LA2aXHoG`mu!z%B2=9n+;TBF&hFiG5qJHR7 zNQae{yXHyLEvbp8OH9VCoQ#@L#M(uYL6={|k+u+7ineeD+1Ljb7IW%ELcH5J_L{xPxNqS%Es$cbz>_MTwGU)- z^dW2WjSXy%-j*WhZ|Rt)16!vd+|CKe^S5lbaa+$Fh%G3ip4x!0NRg@+dtM0H+k-4d z7#D9(dKN#sBCHSH(&>bT*+F77 zKzFS;Q+`J$q^2fxER=WxASk~*S-TRFeUYSS3U?wucW19a{s-oZz?Oa|+}Uy03`y1o zbz?`l%UH5LxeVZNcG7oKzQyz|BKg-FeF=SFvELvCeXu>fOKSet*fBW5yzr(Q*_ktD8;B3cV z(+rGXKw^jRc%op|J}uh8J*a>tlvyC*97kNUgITOuQEWYV#tl)%f<1OAxm;f(*R`SN zj2JsDD8^xjQO91>0t@@mzOCJqL8!Hm_aY zLOtx27#J9~J_18qlgys$bnU_)4Okr(rNZ$6i#fZz&V$N&>o6rG$0x@K7cak+nxu`! za1w2+EUax#R83V`8|fQRk`Tq1*LDj0ZrDz4juN`a?yjAH2_DXKv^ADvQ5OBZ8f9D| z(s5gfkbJ}V7m(G~MznB&Xb%f-%wQZDfgl`kAw8F$4@?*}RaV#x$53gDhr z05XkPd}Fwm6Hzl5rOC1P@->a6M7(6$6t@UUS=GlK8Fa&Yn+ilyE)=()-N&goZ+KCJ zm}{j1BsDxm=;FoiOG=5w!%_+!N16ugh{#19b~)Y}FMefTK^#r<@bzdrKutJgi9FUg zBGd+dsZqw5Q@JZ|0#7{>2yWfBcDuft@+Bs9!Fj?2pBoM`s@u_ z8}UIp9z7iKjj`6}-_S9BF)3*&uCH~F!(ZxyxtaGm<_iaxcVZ?&<)`6XNj^vGW;PN1Ka~ff{wM6WlFzxhZj9=wE8wp6D_Z*y=nk~k! z%Sd@`P|~CcGmfdocr9k=el{G@q&2XMh_!^m*F9R~)F7vJ5ZvRLvSNn0e0FP@$g0^| zjTXH8oX}*hnC7pyOUsZS&nsU15Jj-8u`Fd6HP$hRq6wFuzJ>^(O`(D&qa#Z|cB%9T z0(06eoalzb)UrpqW?gB8K_vXFLi)oBBTpZVC&r>k?w5)Lu^#7H zphvjBQ&Q6?ObKGx3nhF=Xj0_+rpBhvD}p;7Kwh>7E~4O|L=TpGO&;ioYvu{H*Yt}B zmy7Ix<$4I`0BTE5k#k*@I5%YWAz6 zltI%O+f0S&`d}v^!;B=V5@L{WkPF#29D7Y89Qg7jJn`njhBSO6-yk#FodsczLt^d$EqaqgLIq#jkyGr6dvAskU=4nPh!Zg_l4{-u&)`{ueWdRe{C`I*0 zM6o~7>4=Wp8{}lvBt3(1$+YY!YvwwB3lYyf{zOsGXT7vSI$A~L1BO=CtB$v(k@c2! zA3#~7`{JG~om$*Fx*dx-O5z$F6~SoQ6fxZi>rPNjr_;f&_^uXv52Vb9hm;5nKOT51 zhW{%l#;gxyOpA>mI3X88?vRC~epO}YNEpG?rK7w4vx1KRN9@xgpt(bK2_aQW8tnnq zi)C)t@z-=fn|}Hk?1m?E@;=3G9KzMOy#2DdiuD@i0&3tH7``6@Z}d)cv!KJ3PDw_5 zNM%Xg7ghH6H9wKk^%&15sfxR$&9Jb9dye41IpvgOOb6-9S}o~O&ZJB*2MeY~rexw) zsaQ;7Mu&VHl)%|RPYz>tKoK)lH1hgg<+NPQRcrhs*q0Mq&-Ej12N};` z=^*w@64fDrJ1%EJM7Aw?AMW@w7F`KU6{JUxEejoZsl_*nh=-|oEiy0rP!&ZNe*~4X zlU>zbr*k0bd!*Bs(a8Y8icob9PdM)1Uf&0fg8fls$3Mh7!IMhwDvS)=8hetaZ zH9Lz5V@vwFN=d(P;8H`A#@x`9%9so77{Ozxj*%=eMdR|CTx>JaL39%K8+B~KrbKwG z6PdA1-zTnZ5WE!7e&uc`H;#TXt(!!DKaMK7lD0G(;qgvRjYC5x3j3xOmp#eKAf@Su zc41?GbCdVPJb|nXg<9Xl85QKGf{SUjxr+PCTB~phEJ(CXCp^(fsfju6okVM)B~Y8$ zyY?WP0}cEJT0APR>~h+HaXblQ3^y|FbLZ|!6i>U-HV!2-*pBdIr?zHHD5-Tjhl(X@ zd(CsT19`663nwr_O_qwL8=hh+7S>u}0b}e)z`ji@!~>J$xe@R@(Elbi9${i*dox@v2HGwzaCg@ z;)xPdH$0ajXj^DtFKvtGIreS%?ErgE#}oakR!D*ot9Bonj0D*gF8b$_@D6}XJ~MGD zaxQ?!o99oWcdip&;Dj6)EX3M~fvOmLQUk6Jg$(y%Z{e4X$lo}N7l7P7I_FTPFQjDJ z#R#iJHe;L8|G>$s=|v__090EAt3WR%%NLQAyF2g=^`3)#u_LcBx{SPxqZ-Pe*lP(T zoI{}W=O6!&imnSqOqPj;@)D<^#%3snk=Ci!f+XK5?Qbfc3?&ByTFlRwVXGVdh`bz1 z76PukV2};#3wVlRtV=4QuMfu@%j<3eW zG5FPaom2!A5{prq(lSC45Ymem4~wCZ&21;*l_YO)>>0g+M|onQSFr3%(Hluc|IuRM zD1DQo**ds>txy-^9)E!%pcAG2{Wp_I{WJ)KfB}qu`oiHYj<9AFG(v1ft;N&M@?#lK z+yRI92Xbj1OkA9FZXBGAE;~#|Z>1JCrj^c>3pgLdMOY`i&B@3pUj4ona2ZSLRh+Z& z7^-ASdpl`quB=NU0kxatiimeO>WmU#&9>v%>+ysn?y8E>q(<92$E*^!JKSf*@DxmSzNUGUZ*4@G?XB!q6bb&|1f@k zlqALc^F9h-kB9$iVP!qdgYQ3mcD7|esDLV*Gz(hw`mx@^iHsT~m(h-X9>n2~oI=Vs zMC5(IvDb`t)-Peki?=A&LKRTlK1XJVEq)(l&>*!8KZs+N!-SpiLC0F-vQK`BEy&DO z;$2K=0?t>KLxbr0e@RA`G;AYe7D*-jA;+5Wu70Ag015|kk1~5nn&$tC;nTEV;nM_t&sVJm#n ziMViZy_ksd1veEi8F?n!NUVWynz7mTW|mrPakimT>awJsqDVGY1^(8lFOe8QYTmT)qISTt(288BZ8Lfe zBgogNi4!S%8E!V^hRxTVoEm#Jb+KrGsiFc)owJ($YF5x?84Xth)7-)7*A4$j1-670 zn4(>TZ#XHtpmad>50>IU#iY{~h_k&otto+Ewio(M%AxNEQvx$BNp>gs0ja9PxAOH^ zbBs7zGW|ehV#nUFL<2O&ruTKjKT*UjA%dndYRtAlQ@8lG(~)uT*?hR-^D`&z0DPHr z;E5u)_~;NPle)}5QyiO&93$y&-~y%a9jB*ej3{ic^ploN0Vk&buwBHw=yd$R8)iub zaEuhc(BZj!bn;&)s$6Y|>K(zTc@p2wWG|E_N^wM`KNDK8wtcb&NV4HswlT5$F>lEEhOc*IBUo25&utgNvK zuTJ#7;+#1$M#Av>cfOT0MzNG-SC^5sF|TJQe9yf=%^J{3x6h`W*mNaWU3AdwDt(C5 z7gR$}C}t3<`@SQu89R&FsrMdSMUxgpt6v|>ci{ejyfpdD{2l3RtRS2IX855~Q1kkQ zf*y;&!^)6ob};tXTev^Ch26ex_z{)RFhG=sMo)?>F8tW(sOf`N4G}?`Q58;xfEm!W zk*EWGPmKNhl@>qK=S> z!co@DPz7aAku$GkM^MN46S7W_g? z=hPuycgY7E-R<_R@C&D9*Wdy-EiprptaoD8Befw6R2r0e*9#rLqz<;UZQZr)aBsw9 zF5y>BK+U;N6F>wlg$mS>EfKvj(m-Y&W^hko0gY|kV%{!It|7_fIegN0^lR#(QO=BH z+qa$E?+IT^}Hk8yw_{pkVq7f9L4QO(IYmycC3360SR`QQm1j{ z*3qp z3o}Ud`;oK+CQ<1`MZO4<;U6NPVp7%EWGoh@6Rzu+YtEKc&e|yNKwP=ULr>bIzp>op z7@!+5&IkSWdenF(G^Uv_nHJp9)QRl+PG!cnw|!TI+7nh{FhC@P#y*n$GqFqL+@gJq zW9($Ykejw@@1a3jZDv$t%G zvf60{Mo_g<_}gyyO`}4ijVW2fZ#k-(;aMBR$<{n3a~c$>14Jz01N2dKRd>UU$;ahF zQ448nG2Fxv*R;g+C7;Qp53cYP)jLrfKD{Z`aHL*rbrui~LF-NcWUU`==JZ^QzZ@_S z6ne0p+gK;sdi2uw#g>)TL}G>Sz^vjpdLWSm#j)|BML<|5{I-+xKWKarQkJu`8cixG z7;$N0H~bEGHe_pTeRHR*zQQf=(eH&@Qh+Rr=Qq18YzZPw>8+fon#N-7(oQMI){?Mn zbLtF0O08%J=;$7VNo^jQ*$*3w_bA-jG42{%E5;asWd7_6YSd?vnkGcECD!uj0h~^Q zZ?n4@ZsTY(T!RK8y!Ma~jq|qTPp_vNMRfndgT2QtwWL>c2tt%VbG&4oKUsv5tHRa@nS5|Z)Ui9C#~ zg?~`4-W=uL7><5pv--}Ctj4!)WC=xHEIlPmqrD4h=?1b;X|xb-zJ$9v&Wz1GgAhu4 zhyhI#oaN{)!k-Knoa_~ymlz+9Ml>V4JIOdaW1pUmuu<4AYQmu7 zo$VMi3e{lr1$!}#_a5ZEHFz!Rn_=CubAi%ea2XaV=Q#SB5J`JsLlb&?=!G^FBUC{z z1a2kb2_SL!S|X1y>i9D@D#|#bq5OdX8~YZrbD?fR-BrNhTqmGrdaNw~him*>$=Gsoi=t2!Zyd7F~k!>Uf5w7*LHHz`vhm-O{Pg2<&e$vS#l0No*5NN+ znJ)yz@b680j%&@%<|=Y?c1Puhqx>=4$1&|1&XizcBkut<;`@@AekZ;d_Tgp`TfNZT zjRoH>$C@$qR^G1+W^7}X*F?P0DD2X8$-foCZbz8=nuIA{vkGd&<0R(Tg|mN{HFU`~ zx~J7zoEA4^m~iA7%eM-Y2&jBgfSZU(ilE_Prj~>pgguV>BK*aW9&7;m+R+pgG~>FM zTz3SL`Q;fEpyAc!*lEn2%VDn*aA>#yLoG*a+h>EBOx!+-yEa(3LmDn|^cgEhXQ30u zurDPxt<}y_YZ(DAv-sb!u-|cHOcC+>Qp9B}Bbp*n14Qo1#nE*{QI3wWAJ4QpNG=-= zIPy7sX-EZoOi|%K^hBoYAeFJPM|)}pr(M=|Z*;qBs~3kgWOkc&f@)mKHeB{G%{;8p zUq<@dfgTt+;{*_Lfr8QGfu_q@M7sflyd3$w8CSuW+{seV|8O?p00qI z791vXPDI8iXWtiYdmxxG9U>DaY%`Q-(aqXxU+x%p4S#LJ5k`9`gBtT;W3~YTry;R8 zgq?`X$OHXs<-7wK%!VV(_D}{j=KGPE^GIi79t#DU#G{gzA>7}wW?1DV3?VK(3#O4i zfTWx?%`%!=Sv-c5LiAdO2cAB!!3e26lrW9=cgaiZ@MPyWLRXFzEqwgqeOAv8a{M*U z8S7*Tju|752o|GvY@c>{v4fQ~9#Ia)L2}CJ8u_6jk3{j@fq^ z=@8}}U53eTP_9W;aE*U~{On2bs`u%DaD&ZhxSMdYCoDShjF#1VW&CIb(}-L4;+)hN z%7x9C!h6oCIQ;+u}+)X_iz^o(&6I2FV@y{)+|IYAkdcn_v1 z>iN_$nY1>gG0O=8UXTZ5c@)tO%%#p1JG_PAAx==nBx6XT!yc-z#(skAToCM?o7%57 z+-UJ*Sa#$YYhjW`yHNNGv=XqziQ|11x@=!<%EbPd*B(PDF-HNeqD# z3F)a9+=Q%Ah%Abu6?oaiG;SK`hIL1t;qB?$Gb5hyT|qt`!CqKGwr9A{@ZS&|*ZKJU z5CccQu5Vc&8B2#O9N6PV{=(7awbkQ`Ya56v3SGxm<7T#jwKpDMvD5emgm@+ zm@B|K+LewzV_Y{ld0l(p{Ozz!$4Tm-1;x>!(?psuodd)hR>aJNQ%=gv@N)NvBFTR! zT{wm2n5s>xs&sf{EZ|1O?#=tR5W{t6=32|+5HT0T?wdsIl@JnjtHy>X1Y*^4uWr)d@#cV`5g=D z3XgV59yGirG*%6%tAK{K*vk&MmSY_XX&W?Nhg&vtAXBaA`lD@Kzs;u+uXlaFJ(&5@S0Vxog_&*|BBHTCpGH!aVn7FIr;wFf1` zXn_h5h-)gP0JcCHU3IOdE! zBLj+-a170`Pb=^y;+6LD-2HB^u5WZlDRm!z3a@e!GA4)uMqa;oOsK~ECu9~&Feb~C zte8h8~Sk;UsMC1HZa^hdy;ou1%IrTG|&i{nhIPQ!wQ+G59FnM$T zVPY^Xuca26rgF?1MhtS79Ocj9bxy)X_@f~!MZpkWk7jhQC*9dVQY-Pu)c%?2@n|Q) zX{OK4GJS&+(i|>CEmJH%kVc``HqBu*!EdBs#?K`m7K}29Aico=(8u{P>uYpB@)8?_Ne$CJ(aF2`Rp zDkh*UJT*iIG(E=Y(|+(K=G_#-Z4mSJOkznB-s8A4CLjC0P}>8+jOowFgn#k!LL7x+ zawiQl-Xjm;y^gl#mCco-;fE1STfPJ?_klMd@1qbJGkyaNZnYEP{Z2!Mm(Js;4ER3V zaqELkfZ(R!bN{+PzL?LlbU2OMvP(=2{l=n5nw`3sU%c0;Bn_E?z62OV3+WN#yi zzFmwNnJO@i_bpAI4&V2trqdGN!*GleY^~)J!*g*fIW3?ZN`u z6#O+6h`Ti$7iaP4n1o@4k2va#bNbZ_mD7^~8sXoNkghaU@A9wl|fiPs^KaKfzFtN%01ZA`0(z^M|wKl@O z!zZ1v42Mu(vs>Ye?r%xQjWf8Am@moIW8-LrqU( zbv!2Tvy>;s=tk%wsp(Af5V2W+# zoE$aBkbMxo<;Jy)ED?>IdftDGKGX$(D|_HdcJf1x~vhA^)j^T#iTe|0J{0#?gO=@iBA z|Bd);>g&k8*F|U-{~NyRC^D82u$Z|l)oL$;8PmU$iAG;(dBY&j=<*NWbDT9HC<$TE zvZ;h?^#4J6j^<_#Pwh3E>-&y5V;nIM?b>Ej8=`UkfSeq;Y%5?g-k0%1$Cxo=8H6y} zL&P(_ACZrh8K<<_r6#VVWlIUi@>0H6%T-&*!9dE}8KXG&! zbEBciyV*klX{V1XI^Z%HSsCmlVQ9 z?%WB9&l;UO5q{-(Gv>Z-{Iap=^S>Idfny5g*v5>Jr(a_gFr)f^ zz!b|d8vN^B&O-qY>+ATw)KRwtWGvSs3#aFCoE2;%3LBUHHkb7wT;Gvp^z;RV5xzc< zM*AD2t*r7oxLfjQH{8Hc?i~JpeJX6>sKOcD4N1qh)TQ&1TD^Paf8j=sGQ$k3z{tB+ zK2cyJ|4ouJ2%y&<-nWW&%qW)Tay;JfTTaa7!{6Uv>rL+-DwB6(%HtpyZ(_Dd^CnKo zMZ=Yp?{co98QD!q#{DKc8XtE@ zcBC02Qr{*=Fr)e%QgMK2&M%CP?H*?uiEs-?lrcc?>+)hH9OJkpIq(l#zwEkP$V{zW z)m~n1YR9_-?{+IkSu>rO-?l&#;^NVRn~pQ6gF6Tqz*5Tc(b?v)R{4W)YbWIZzA-MUFOJSm;gE_1*M+kj&(7g>tQb@4zg!pjs&y^IWH6 z7GD`MQuZK9k@tLB;W1fTDU0@r-z~%N8`pfJJV+}!GqyQx86FZ3tF6Ip!u8=YecP#z z##>wm%!zAvR+kg!IXxKzdY|P)8PaIaCoOy3Lpp1#qnFGcJRsK_pq*UcI5R9G!H^gC zXhye#bfu;J<*kKn6X8Nfl`((xc|E~0qKimG)7v_v8GJh(SH@b&ASxX^;u+sP$w&K= zJ}P=4XVmPzm!r#AaaO!s1(Y$}n@p^+#rCmd91ZqjvwZ?Thx<6Lj7>kokXN$@12o3_ zlJQnxEN#inWAc?9KbeJhIp&N*2qi2bFFjYVO~e>Q(1XbJ-E4OgGwyE3n&Cm@mxV5& z82&i%r2;h!Ztu+G?4kX0VZxDQbb~&&O++)YNs_U377-iEJg^h?IJOKQUIC#mmV!P6 z(HJi#BZrsDmJM%zLs#GHSa;#?h783CMo7~W_kk4Di1(40W-6xqbPPfJ#wCt6W3DaP z4^=RuyOead1f3s`V`7xB-;rKA{9Qeiyt4l=;+u{s>R>M|Ru;Nm2?v~jjIq4H5bEMl zA&v8(ajG$o4WEDvgWThscAOc5Uc?YWk7tCJk&ss5$yW0O<9_fj%s8%$!Q8$sWcC0o z^TIK@fH!+Hk(}T zh%@3?3`V%^fpOMuMmbDgo^R=~Zx|o8IJ1T=4lLOi?P(iLTql>kjt?4M3_ai?tLM`} zlvYUhqgXCZ;=ByIg_%(n$D6BH;vT^JJ7K$q3+pq%S3!;X0i?bQ0MoJt4re)jF*?tW zj>1qbehLqCQfdyVCBT8M=YcdP?sqBf_7G>G$`VkoCsQYR(}Y#sgPg34VaXt+#_VAL zzUetiJ%xDH8Job>gJXNB+Til3~S`aNlvrD;u{aGo>*Nwxf+%nZN~U+5Xu@)>qb1|Ym-l$rifE% z9dDh|tmxq(j_!P^h3@*!EnBdq*BRC9m7{Cn_!fIhONxX4mynF;1c|spw%~G!ClAYx zC&TtK0C_EY5H#ajA=mA|)icOV;l8o3X+3h)k^k?lPb)koYmKrh3o%=;uR9?brO;;~ z7SW9E3eug0Qn0)Z8s2skE;S@39X&jI@je$a7o3c_;gxRKQW^FzjK~yrsF14;_#04> zJkT%yPxr}(u2YoZ$uKNYWDg$L6l_odn|~49dUS68Y`D_#W>iT3P+6iG*-4UdyOJxD z!|lc6IOKcE5oI{oDhnKiF@{Yth)HS(eQ-yMY)4(?cru2MK5HCoM^*Qu9!kR7;FWrM z8l8LA&mQK;FT)px*ls;|Qk^}YmRPI|evgu9%;8dijTVw^wAVtryD3lM;Z8}$RE6Wk zfD!sWh{pN|veJGdx4!E0TOn5sGu76W9;pbO?(v=YiD$UDb|kKV|c7%&*;bYT`l_bR0TEx zkE4JyQ2gfR$N%FtBBJ7(%-Q&OCt?5aMrdI580z+2204rfu(uPC&+( z($n@5nz22JZ0zw^HZv8-zJrIOo$_Qym$67IExjvPM)nkvMPp%#6&#I)r#hAGoFx*|BuOEiXKDo z{xqV;Ugmf+9HV{QB?@L#FDDfPguUYui7J}7#k7O-7@Zcpn5QOrD-}u5i>?~?tJ^B>9KFq{$Y`2&76YwCy3{8Q;6fM<0h-evIpp zv=C;fzsC`0*mH&@#P;BUO~Id00gY+%2VOQYgN)m_d>X#n_d4>7+BFyMv$$i}Ivv$-Nh z>gb-0RXun7VMmu?Atw-d!SrO1M*7zz<(%LxjZ2VUl9sZrqd(#VTsFKZc|g(OKdi8r zroW*kR`dFr>JRX*xe>>RElLI}BoGrEtF?#_TpCr)AF>7_`Le5rb__2W)M zMoA=GZEJR>yoSZ3eS*?>=(ZHbfgKS{)3RKXNRhGPIegNIJ2bq2O2{Iw^jyPa0{@l* zInE&=9S=YsZZ9lhI$7O|NaFA*rzWG-Mi^1j2hwQ&j8&9;meLLW4bLv2xIvJU>fIF$jKE>w7zz?k5A%Kzvk+!WJB5r zt?*UHo?&V9G39!JO~ThGfjzJ=y2oXC&j|jnJMs(%bO94z+>Qq%RAc@}GFNJsshh$# z9OurfUAu%cvTu@%o}4M%wLLbuhj%%{kA|O1!{4_Yb;inN1rSYy*APx#xCY;}{1dfs z^qIeE+vx85Z=<(A=)tV9yH_oXYw_`=V#B|ny7IWWA^$IHqFC#9DT-S zqQ?{|{zFe>%KnAQ%5Fpk5g}hWjv+fG8A}QC9Et*aFhFDcH!`x(#ZIztR1#x;*U@E+ z`h9wtf*IAnlZp$}M1_MCTQ3OTb6gp9+?PwxjO;&1#?i|HGc3^K`;INcv^5ARNPCEQ z#`gpAT^D@utm6+I&3X9M>8%wM$nbwe{AxYnkZky|qq*Ak1TdrePg1cvrbOyE=wGDh47d^;``T|T9${coz} z=vnM%nuDU)E&Z93myz7GfRoZH9(&MD$^8PWQc-NORP zn66{*XdWQFEidlqT-WhsyrbdBJK94T)R?bl?`RH$u}SXRhU+`dox{u35QNhn6wcUw zgKXSM@iVgKxVeEN&FHcoNMG3PC{*&@+>jcg7erPlX=!pJN1rjt+iFB;?ZE);t$&k@ z93)OH270Lvt*$q5#wmo~a)cR$93h0y!5Q6+Nyj~$(%M&x343L-#-5V$!Be=2Q;@Oz zFQJNx((?co6LwQ8hh%{;hcHZ#n>iI3<$G~Bx4|FL)6!M)Fp za~J+_h=nj8apbl8fg1DgkeNV~zolDS7!x_|YJG{Ahl;chja_yjZ6fx+xc496WUit~KZwy2Q-qf5)H5HSWE#$&* z8^?ZiOh)%WGrBvG?%F6e=GzK)b{t!WmuIKDs6yq% zh+@!pAv6byE@nQ)XiFHB?XBF^QDrzC5{^)%Cr+#p)u``A>g$7=CdM3+!i2LN-MPcx ztYTac#L(|fbhirIw+gfNY)5j>;Uu>3l2@_^tip(AeD@$9moA+avTN;IS=kWBKfPAx zIL3@dAs|B6180OIB$VtuC_cRfHjFx^ZNuNKQh*9$3|s7#QgS!@A)M=oGP>4)d~pV8 zq+3Z!6J@=YSCB8C*C$1}q1B&3|5dOIuX^l?@4Y>Q^ko; zgt{!YX&Hrkoj!8`BizMfLN(@lllj(QE?JDt4czjo`#$_B+{X#XFj7irqM-Eb&`rpF zDTITrj4K?Sb~)Od>4Za^5E_cXj}e~d9b-!vpV+@Y>~;(pYsNkeiBLu}P8!ZyWoQ20 zW@kzAj7&JbtW|lj6D}{-57^iz$d8s4>$l6E;)U|h#`C)&tC9S64KL1ivSnL zZmi2~Ir|;k`5CVV0HLZN8P61XB(wtU|A0f!FgmK{6#9SxA0%+a=svc*hSLMnj^pYY z-GXLhmywL671zSky0D&cTp51ZJ_~CFGpboq{YI=9y_wLr@I=5buR`Ni8#nqz8f9A4{DFImYe7Yux1q5gg+mB{wi;h3T>>s$IuEu4wNL$%t;svtdm?O*>%=)x(y*k#)_&BM&@i5Ej zdv&1|mK@{%)OavpV{en4#)IuT%x=uD^3dCIc!;CUF!2pU>eU_+qH&%uPV@vAJ zyX;B1f*NR@SvBliZJk0Aju0I8J%^7Y22rWjh-dHIAs>5;MspzNW9T4hc-OJz^qAgU ztqNvT8>DK0%KVVMCzN9%x+@)f#!A^RN=Nkv?=`@uD>yuv9bWeR^i#3=S) z+QQw2N@6fAo7BSDnE}+?FXZmm~*1cim3QfxRu};kc@U0;Yx&S@BtJlb93Li&>Gzb8O=mj?LDRv2jQ7nhYJ53oTVF4or zR6HhBV}1ge#Rf0M*|K7)VZ2Xt8gguK0~84&50u=WV0}OyPzjL+p*=`g<=;63FSa& z6Y={LQ5r(U!TTIXdo_ko;uyzs$w4dErNX{AtZl4^=Q*;Bew%RQ9n+I0*cMcyem<#b z`dPX}=3a!$;02B}!=Y>l!f6i*XKXJd8#g+9L-Wrt@Nw0B+>F)c{0C0aF~AHNQa!3D z^B?->UTRbSBC4;fdt{gP#ZFj;_0YF_6U?aokW^(mWk2ndmz+M6nI`h;_CPRW`XhTO zm_wZ|XN-v^e2g!3R2lW30E8<&5zff|m}DH7O$jX~Ib-rN$Coii8b;;S4A2-~PDaj% zwi040V_TxX!jWc#s2hwnrMRFfVH)o%$;*C4%M0ccf|cP*SPZXnlo_T`#rP_qjOkCv z#Pw7f$~Z4_gq+#HiQ^Dn?I<%=$q7ncGd)#-O~9X0fD|#$<>D^xj$~Sx<4@r=jyz-V zlGDBdqlMgyYRs=CGbcc9Ov3qrbS$IAkKuKWJL8yj@5W~jtdYN-j{f$IUUE19|mN$o^LY?I% zcjP+ZEvK)*u%w#p!2_Fuw^9KIUmPcEt#0F%Lu>WC@HR)AG5AIRVXc4})!RwMrJKbt zaeEmX!qp?o?{Lf+=}`<%dsSebziqO2?ZHjSJME=o13BDYr8oIqjymI|`?N3xGpcu! ziUU^Md!LRw`R{RD89tysJNXgK$o|a8qAcuVi>3VD(A-bXU_oD``fSB%7n zr}sO`i~%a)SUqaQQwi0m|D4oZ6s(^(ZZVwktoa8VZ-xWWK>j~%X93>Wakb$TQ--wR zHc6Xu8*O$sNz+i*AbZudB}bAMQcz`E>vh(Yk-fW4n=&&qGcz+YGcz+Y{O3D!zY9mQ z?pXEzJnd%XwZ8Yvy#r^?oSE@8*D8|velSlLX2%I)dvK0XYX&D}G0X1*#)`f2y&R{i zLsre{_-QAM27V9*B48kq5!h0yxDOdK0@n59%L(eE%8O%$BY>P6);lL@^@Dy{NsRQ zgk+vGHcc%p%I!sRt>l9H#KzeaQaC?kRLTA%*yypN(_HHQV%Sd^W1Y}9GUcVWma#Sov(o!N-i`6Kr|W7FO8--TaO@$puv^f<&;ZR=EzVkBuB zXy*4}CT4~V#&CU8k0F$q;SY>q0jm#`Qfv6Z=#u|K@G$^r;>3aGikvPjNxeTZ)PU|P z7Eo;b337z}7%(KuEjyVRxRo{c6T=CZYVVIu{)jT>C`HCk!N7Z8k=eBjK)dvzJf zi*mx$p*gp-h6++%W%#vxe(2uIG>3Nm8g{|gVwh%JA~bU15d%KI zG3EsHPgK&!!4Fwk(tis&+MBBYmZ?k^pg-vlrxCx05twq& zBOl=@z3vYNA28*hh?broVns6l2qs1a{>IqStn|eLGtFhBpZ&>j13X*`Ww;qtvi}Tr z&paWx<;)ZMi!mi&zGLIVz9N`~<~UC%1*3(3g@y9}b(Re;F3TYZ?r+AhN%{Spz5*VC zUxf@@FjNw)`a7(GGl`_1rDfc_r{{zI!x$1U-;WgZ!DQ74`zK&%myCc!NAq(k_Adhs zXqQw{DnDdpN&h$Km~bK%Th|4g{}|xb{KuUM!>S7P{|kLg2a>hHdAcTh`Xvm zoSpv!&FDJql}NZ62zZLAaI?g)TWx7-?&^lNBcB$__!`1hzd8crDoXIt0Aq!ZlcMU< zVRsD!ykkC)UsoPKh!#251P6f`#314gD~0Hjxu4)#h9A%$OwZ1t$4HMA0VG;?ZCIzy zVst@4@rc|WI3t(d$N{nvvT)Zi7KJ#Ak(53W=1Cb{@~;a%#*lalfYpY0W^p}359lFc zA;rg^(z1kKA8-tsnCqg0&}9VeDQ;lE0n_=;Np41x&>I2@_ZZz$X;F@$sw~d0xnm44 zpkZaYrdWxb8-athLi}KP+ zYf4i2+)2imv+|9}T#7*H0-KPWiv;pQM~hie?NHeBQum8>eUrfTyIC zNVyp(=q%WyO-eWEWV^>-|WT)MG6a@IIbrNaq#1w#&4Z%&k= zx62dm(!%6#0UwnMM;n%9hN5fD5myzekZTpStPBjZIOO%|J)v0XVptt8g27A(Mdh$962C7#)sg)ci1PJr9)(AlShl>v2Yy==PeMD1e{*}bFu96K&Cz`uuE5a+`76VPRPJ(#?$W2X4k#P|vr(YN{djhZaQ3TCfaR?HpKS zfSgB|(d{>uT##=GHPixrpdg8}Afjt>ts|}JLbWJ=x&sCl;C}kAD=MW#${Z+|1h!YF zqA{URs}EG`lM|)#NX1=hfC00Wl#+kfU6pCTK^TBdWmxKJHzjV=Jc2aJc0m?@llMJu z?5N~FWeR#VHHAOw%AiFHum~wA{Ozb0Dh$_$*{3ZUa{`wAty;#QP6Vx4f;BjUiuDAG zcuhCgmLrmujTHgD300KN4~ZnHmysH;upsnOTgBy#&QJq}tXM^{@uygm*fy|eW$X+q zk`<#-w-p1uApiYSLz(V2=iy+(Ym3O3uC4ChKX=5R6eiW|-o}!EG%pIO75vauowi&7Tks0n2U>D(Tw$<1 zGdxw3zwdYVG5ibiUqK|I_zpoL?+YYG)dNc_ZTY|4>AbXG{3Ulk0}P0oP(q3P5b2S3 zfAA3Vk|{#8F!TUJ+E^~O7oq$ESseBzat+~OiBh`<8Aw2JD51sShe(gS2V35t99Z9K zF1m+o5--vt@1f*jO-3H=ERF!2lAzAR3@;!gky+MBX_57Cu+aZSQ%K1-U7eQ9=$3ng zfdxFwF4NFhkHAL)h&e*^%a!>SHlIAo&;sTNU1(m6s7C{Zc)ky}>4arg=AS;x$vws( z14fmO5T4N_`LQ4)$dSI%a(8onwS^u}b~fR<%*PpiK)**ht*!ik>oSct?RY%wxEh{- z+%na2PcX!QX{O1pP#vm25$arf)F}ZLES_W_AyWdW=UODxRtk~wWK!5Vu?5gQ#ZUt3 z3%{Rf>JTI8sUY1B#&8+)3;@0M@nOh-CI)sBvzS`>|YI*dzuWwn*H z`PPh12%cfA>DMbuBuRZHsAxjor@;9=aui2l$p6(-k+v#3m5FrbLx=QAsre84IN&QzsAG1pPm?cKZrJh$AV!*7@s&##n z34+$V8rGnSGpjPS4C7v7%m^5YDWiCPNNJM$T5u86kmI-|M@0X0uQR-W3gf>X6*g8P z<@Kbj$ZAGQ&N7!j-5WMe@n2U;N{N&=f`UGYqsEwKM7uW`P{7^?DkzE{yc}t71}zNwbZB&ww%jB%zu?|w zY^dcIlG17fKcMpW;LyHz!#+#~c`F-YF-V+xkFg`b;irV!!4HuhdG7@ezHpo?DHn3c zp`7WxSnhp>9T2gPJ+CT?}s4>Jo14_@LZz3a`2d*Y3x2=YzRmOrBdcSWMxVJ zAm|vnqCsI$cGAeu^&tZd@MF7-Dqf7J4+Dj&&P1T`@!=8okv>RK?vNHQEk@EuL6ZM- zGB-B2vVuW5du!&$3^~9{?BX(Y)utgIhaniSv9h@)$y>7h`x6GcRsK1rmr5^bdKCgb z2>@nN{y67P8SRbFq%sFNe;Vp=?&a>vC^t1NIb+J+d{d@G7!O@?gX8UnK`@&5d6;-r0ZC%(y!(Q&AizU1 zGg!z_`-{*<*Ti;=GW$TLgi5elErZ>c3^JhhQZCaibkU|AUxpngh#hf4Y(dklG^xFf zs|mhhjOei_5^JoJRGU?%315W?7!}}IPc#=>Gjfo}j3l3a&5(me$kYm7N{g(og9XQ8 zr8U3U($k^p`ZxCt0}GhQCK~#*laF4K%x{8;YNRKEe9Le)UX9Wx=6xI5XuZhuM}S8T z#hhLlpF1+Q=)Pk}A)c+M%s@p8)TzlLeHYmDI+m>W$Yvc0toywG+R~~MFZ6rHf(bD+ zryJzLQKY7J@Mm2iH0k>=32zp)2-_2oNG{RMgYE~$ihyx0Get{_k@iE->=b?bHuodL z`X8p~+qV(+W56(vkkkZB32~3T`-vf)lmBd^uj?~SNfGl?VA9hh?JRvloBNr;g;b{K zJRs$f`Icj6D{+ov(mKT&#(b;%s6|=r}jt7u75EG1Vj=kqdsIrwS0mR_CG0lIRh=`TrRH zKKV|-=(wRB(lL$J{TJ53*@_I%85 z8+Jg1lXAV?pBO=Nj)pn#5O4uWZPA~2dkupRm?&oMFNt)>xF#5Ic`!`sP0Bt3el3Fu za6~fiGLa(b+91KHjT6jqqJUh0BQE823@xD3idFQ5#-CzMVy_EqYI(TfbE2`=@J34~NaW+YLrXF(mLrDz=JB>W z#()DJZAZ-5Xp(#*km;P)R%YV%>uzkI0Z%tmd(vX09Sho3q@1#B=8iLffKZH?wu=gt zkB2g{OIBCsW(t#&rD1o1(GQr<>6i6g#WDn(2mr#+Xk_w#cao9cBL9{%NMxRmXi)oP zXlJ_qRmsSayQpts82xtrUXHk%cH-no${gvG&BCc1ai;(UGxkkN?xMLEv zxrKoS#7?^OTB=3REddhuK@#|qtqa(IpZ@G_Wx(U|g`5gI-Fqv8A<&##!<_6CYIt>F zD)Q@ZW6bzprcjA2*|!B7O^Mq~3oDn;>HWS2dqIBbV+pNk@h2}x;O$vhnbv`4 z$RQF#2U^nyr465HfB~iCJ1j3Pj`IiZTw}_fd{a`|`V>;1d$MTconWMf zp^}qzqGRX%kv-=bn*xFrtCUiU;!ky%3nLvodu-47FaYUBv5SgXvZkC}V9)_RVJxEP z_!A{r>I(ryo0FTxC5IR%|HXfk>VJ^|2aH|u*L@H<`56DL!^(n=a^| zZrES~=Dhyv%1J4aQUnF{g?-G}(yTu-!;Ki$h4NcDgD^#u#t*R~nWJDLpyZ=%(OI4T zgWGAS0kzbJ?=orp(SB476B1hj7PS;h0R9@Nny%`}TG*1x`MubV=U@ zIvzBfa#WclJUnK|0rCEfd!A7vZyY>4K8-(79zlk6{ojWmsXl9l4^(t!3@``AqND;I&?GDxEGBk z)?gxDGM4dWZwB^=L>ma|#-4yVYI-$4BSzdLaOzbt$J5Wnb{keeh3Yy6s~TZ@0F(d6 zD=gY0&hI5vbI;RDt>P;d< zOaqux>}wpJn-y1LV0GmH+s{1>H()pU`tPwrp4K#B4g4kFhr^3SBlcqfj?|elX7orL zV0B8Q^ra>rGs?7J8Wtc3i|!F4dEwApdk#Bj2Ws`*{;zJvSP_!mMY+g`b;W5&OBkyf z7m{N*&RbbJ*jjY^#i**xwH<()x&+B7E^jU>qq)p=PCcb6J&k6N)2ZX{3aL12*$g&BoVkwrdl$d!;1 zOIqNZWY#t0a_srF_FUI8Ck)~jfXBpqX?~_L-&~lQX*OC%mYrMd#|C^8=SIk^%)2Pr zM{XFjVF@;1_{P5{5)FL|%f^mc$g@a9*0m$~73I*D%U}x}C-H=F^w^-FE~>j0F=RW%uXkuip(A2#r{S5y&BI z>#pX@4Z26Cm=r$04^nX=?*$}c<+_} z^vaWl)wS(q2;|=vd^~Mm)$V7wK|OCsRa1FF?+++E%A{A6INgGKfT0KVI3e^bhh{tw zW?=4{s;TZl#)hC5pAzW$=u`hr_=5?TvnyM!F@+)1J;cC+2Hc$2p3*1#p4NFhj4(Z>-}4CQU8m@n!=zMd{J;$Jf z9&!#k4Iurwplc1^@4J=f8F0`5p8s~|ygaeb2Nu1GII!{#WcA6rEiW+ii{)2xt9L#< zOQ8`jgb~Qpu+F@DkujskL+E3!K>mxt$D7A&DSq=WG3?EF^JxI-F9jWAxbIzLg;g?S z=H1H-e$&SA42DL$97bRaM;?l{^H&)DW({kRKEba982#E|*(d00{;Lc*=)vdLy%<3B zt664z7gIy`8bjWUp^W0BzLwM}*>Iw>!q*vU&=etLEF*#F*8`0e;N>L=S;>SPp^j*_ z(spk!W(19BIXzuB5UqJ5tU=UfZbs(j{v6Ub85?@U29l0G%H&xG^q^idr(szL zt@tLaKog6j0&Vv#!w>4i&@=X4OiT!be;e@Y3Ow^=_Z`CzDt|_zYYZau8#Lj&FyY!L z|B|%w8NY({J!3$SpO}&FYCsA>{P&4R+?%nl9~gX4`9oTJ3PJ;Z2m=rwV5^BDtv@n0 z1U-VBI+#V!f*->IB#&y;1W(bm4zw2an1G)cD}v_8IaYLHXvt4u2|9i8qUGKKxeLtw z%owmK9Z)P!@XrB8r;m%7j!4(1E8M>@>>h!*eCIr^Ozba#MZYK8u^V#6$cp=wL2gFB zM{!brP3jSP#=rT0pi-RF--3#FE9-h&{owLDgWaSsL<}JM_duhIMct0ho&JMi2i2>b zik--l{6~<{xMefAo12mY!+ihtCqwVy8RyrmtTxeq1{%+MS?0a|dH=;wgUZZ4Ly}y& z_NlQv!G8r99lFlRqt&{<8FWyrE9Y^i^vV7^*m%=(3(Z-7e3bi#L2q8fBW4i)PvFsw zEbHa&>QA)Xzl;Gv)jX%{X#nZ}X5rW7T9Tt8mkunr{}^`AE6-sk@+AKkWK2xZamvQ5 zqa>XzopQJt6B92@;+2G;wHs~DyU15I(9Lj>V|8+`0xl|8@{HV74R|x2aUxIh)j-y< z!p-_l4*VD-w2JS!h{|VD7=tt z>Y_Wra5rO$kwwsg6JY@wnB=a+E0pde!w(vn^J`q1K?6>P0qD2&ym7w*dlQ4-jD9H+GQf-EU)EXe z${)B?lAv1ygdu}#*|#yM%@{HwZ8C2QCfaa3-;k%|ZfC$jwJE3POan;2J?L0AlkD+% zcLzi5(PIX`N(hs7255MZ5-C_(b_IhAsyTUeR;3Bt0wBiYWU=f_0}Xnz`MqNdAbKm% z*dpb}l!mk=IYC6DKiiB6K~e9Vm)k+19ou0C-Y~XKxw8!VLivZj+YS_oIU5-C$C?Hf zP0`LVw9V*`Q~G4z5p0Y?;*BlJ;E(?B+*vp#g_2lC?6@H+#J zSBnsDRI7Fv_GUO3i9E>zAY+(|mV5^dHE1ZvE3wxmatKH?RgEzW8{lSi#t2@MFW}rc>CvN~q0Z1PQ9W#_TXVkaevf&3gi#hx(f)-R@ z0a{VC?l57MFWWsJ^LePR!pa}_v7VLoq>gUZP z8w=ZT({am-#J0Yj4!KP?Nypj;5Z<+1b`?pA!sc< z`F_{F#6oDrEUds(#%3bu-2Z9X21R0)fI-`u zk^=w_`mu7^z&53ACHh2PMs#Xs>L*NkYH%R8Z6K$M@zOxNfz(r z1|QUn^SbfRO z45?^Y4$ZhP%s}pP(&_u=eLrJI(8!VZ%ngJ_+#g2Zh5Mw){q6w<9_0Tg;$4TWNSn+D zf~j5F+#;X-gA8`l8oBILi5SE`7|@A z{cxbKBc+zp121n$YOrn)dW4||1v*2je40WN9tjhWZ>RMEk1t*(bdNHI1a)&E)h>gf zC69(Ba93mq@DJiKh9BfGhCB!oh<+^4aMj}M`RE9fwtJkhp~tXJS1lxqp8B-l@vs2( zUw8fM_M|5ma?lVLQu-J{_!9v~rAy~=`cXUsD8EZ8HOFS=95$U1(hc8nIPiP zqhr=xTC#7)2V$OO;62XDOUC}dC`bp5_B@+UAlh&79AiX}c9<9u^7OqvvCjn-?J!DD zmwT9>XULm04#fbXpAR%fU^(4~Bk&6hd(%eXghBiZS#m@Qe8BTXhQ3K9j{!u#7-%#% zNe*qfXesI?{lN1at`vaqmlCdLsYGd-FEj8>YwIZp4R|>Wz&71k+}9~<4St89KNQTp z!dMd21?RNv13ZBl3FKNN&lLNk$b zt!kz|vx2$<1y_T7O<;pgOUy1r`nP@BxH?75q8_4st;PoY0s+`0D}p z*I3Cu@o2Yp@_gJIj3K*2obu2TS+>UTlWqBrt!EH6oS5tZ-oKcS4^yp;4SId)o(LqowfeMnLeYrJhuhGcb|AVT}TO$ z{dUn)zg+%pen~Rpl=2Qk>2Zj2M8S7cm{^LOcY=e)HX#Q$%85qt!o#}^s>d1s9wkW< zYX|0L4`Vz;d4+_RJ)pScs7K0)ko1#9CcEiB@B*R4%&r z8A^{6QGJnQj+mk(O2oWBDa()?Amq#P0Yk|xiyYWGpOhsQBIJXBAe23^Hm;kPJ?29O z)8n{aUl_k+oq$qeM143xHIg8Z`-nmHIH!Ews*uPL_EErm%^Q)0Y(1_~E5pYOF1O}k zp&DOL%9ar%@Z$g?zB92_Yh6|nAJad{PZ(a0v!E>3YWXFD%5B&1SrSexM97x`@%6v7C|PI{Q}&>*7*LNxqJ4eTl=6g>Q6ufE zp!wRU_Y+1FtFIYW?%V3p%VQ+-a)f<7f%!wmeZjtAV7XP_R>qVVQQrg#PRqnvNiTM2 zjJT!CTZ_JTldZ#s*<({k)VNh8^)$Pv68>$#eY?Y*=mX9**L+dGW3U&Ah3j~W9y=x9 z7Z;#l~=Hcd3RZ{sRN+ zam|!3oUJsSn#BGPSpP)*dz9M<{S*C>f#y~oS@}<%Wmb%|AA{!GIhwc!{ltKB+xd!o zH6g`9g!~kc=!LCH-{UDiGn8CUZUx^>VPYwAehv=0$cDIba?MPu=5M_Hg(3A=g7j}o z@_v`5<H)`fF02 zp|}$K&2VzdldS=<5FvjD+rNQ zf-K*aL^pD7q|=jGtgq--Hn{vDL%*C<^^_PnEu z_`ad08D!dMuWlH*eS;>qC6q*poTHPH#DnZL3?;WDnL(B^BwP~&1kt2Uk2L2cuzD?{ zzcsH?Pc1E_=Eh!y^4ErZ)MV;zRc_5S>bXtEs6&L}*M+#R!*bD!YN0EDxQj)|S3mg`i zS0m(jmPsnB1bNY=%)1i|sn0T{B#Ao_IMjN-2e7@(on%-&CgHuFAN2@286Z47aWz_Q z(cQ#g`h0j^jgXrHf<|_r*>1>cr8~t?dbnJ@3KPi@b1KW?ujp~78A_jJ@oI$JjAe9Z`695JT@gCXJw?l+e-qE_48!jO76;k}+(qDa^+0n?1_<>mP`cPqo`G352) zG$BUBtyvz~CKUxL+-(e}&+;USgxwY})VC;8#NE!2`g})`95J_NnWp3zR#{rYS^jr0 zq&~}(C=zxCV0cHmv&9t*r_Xn!Vnl2K;wplW>mJ>i2GGM-=v4_sit<|_kGCR6P)#46 zS#{eCqR+Py$q}<17<8RD5f5P{cb4Jw*>zHnptAu&k}jq;?i>T@F;VIDyr4zE9Ra{1 zK4R0@zuR`_8cGl6w-+TAB#?7%*Mq~rpAjbd&OoDb6S%_w`>foN95DmHXgVu4yShOG z>9ZHmovlO+0ihm&1})vNVf0xQd_f2)0)j?*xQ#7Naze|9!SvZksYlQ#Kxjj9OF&aY z9d4%~_1T7EL83}P;lbh3!{rrs7sKiE!Fe@8b^(GudZD@O#tfm)K3b$GKMr}sdZcu+ z+T=T(vcdG}=B6Zxs{n@u1uR|6G@TrC<>a8!2?N|Azp+l>yH{h)h!S}*km!Waox7?b z_1OtQi+~ycs0M!F!PO0-&uZY+2$=)~^LvfxHZ&u*?RFc~o%?%kX-xw60EovX+jN}U zYe0QIHfRyB4*>KCI5MI+CByb52GVDbKs|!)%91R~>9Ou^2GVCqphdvl0YD$^(+=-p z2z~a^Dn>+u2ssdC>9D)!<{(szh-QqCm5H{S+9U+Th?oWfW2W44D7Uz@-Hd_sIc7$3 z#I%69vS1`FZNDM(SmNr{vn<9To>_?NXgM>tw9s}344}`}KBsCd!5knM#9Z@mwB~xL z;q*C(#ezf~1WFwY+&$^$4W`e^EB#X|zC~dH2s|=z&c&T_i-ytXBlBu3#}XiTWUc<4BH}HZeZ=v+Y(k2NTH=vkHu#KFzIQp5P7{ zPM`g-WCN=nL5D?lRiE4P+Iiw>G~E&T$rWx5xV<-(=gAES!`D#x(d^Phr$3<7QNlNP^%AA-NOvC$8shsi~qI)6CpAl4hH(TrFLO& zqq56A!T<{LZ#k_`zN+ex1f?GdX}ql!_y&b>op|VS)uRj}pda-bz7R%^yhnov*IDc+ z?v*-O9x08w#~4tSfx(_tFc5^>htq5bWGq-Ty)i$(VgV@AO6ObKs8R*$@Ak|))? z(x??Lo-CH@rGYW`EW-;3I;2`kT8gM=19glPO_q4;6C+~-qqWA)f!)Q%=#YDkq4jXu z{J@0TyEJvF?`k>)$$T!Dh&;dnT`CmEN`vBIxaS#Mz;w_H=%dVNk@S3!@Zx;C()=2& z!Y?qa0KeBuD9fmk_CnGkTk56p;&5fM?q0NUT4%|qM%s%((@FbGL7K_%KKBxX*&+qc zX%y2l{$U zx>p!hUlqb@k@QNC5M%Q_du?o>w$r`Ja00r{j)6gyNO?6V@_*^d7MrVufyv>LBw?1u zijs^yR2eRnM;jw!m4Ui@jUfm4(Oxp@!FsCGn%BY_JY9JUGFT1|)CY>ys(YPb2e>JG zjTs?gUJuNz1k(`T+O=k-LX9@6#ad;uI#iUuTs&E-7RRL{tI1}LTHU?D@B_MVDr@Qa zp*M!sy^#+AJ|)7(61S6>%bSc50k1yel*UTrycrxgAMK^-gOb2HFw&STm-f217*IgF zi4^>+&ZrUgR=_Ys^I7aF?vp1yFznuDa6P(ix>VH2JX{Kr_;wJ{ess=Jt_)O1YwjHe z*2A&tF@f=71icfWRF@!CXK3fBdzV4=)g^c>lHLtc;=)&Dy5!ztFad3&qep-c8Se!n z@uhrjyADL}Go*fesYH&v_k*Y7-qJxyRg)=vWn`pQth)~wTtGGKC|ImU+6S|x+gn9? zla}s72G>vN5;^id3?3?ByFFjnIZ$hqC(7<41{E-gz}J22N_5EhC>ST1rWN^#waLMT zGz|AKgB+1x&lzvmZDd(#TJdpMf%y`=#zL)860dXAeZp`UEykvCQ@)`u&5 zWPg)^_2{kGHFi2vNW5b;wYq6R!TS=;A+W)J~`MrZql5-C3iMLk{d zs2g(B0TKur4fhKJ3V380mpYLm>6aj(qln5=k+8hXpZ2(48B{<;=qwY}Nc%NtXjTjD zIeFNH_Vj_4{s`E~^5|^r$A_?F8dxg3KN)gSet(@VFd(XwQl=Guh81{$ zjRvM?ns_Aj@-K$lBO05W|ADnJ4Saa#DWgc#$9B1Y7(!p2yw@V>pCF+!&de98^|9ebSz6e?3@4y6%Gb5Vr(}ruHxMV{%|s!B zotR$^Nf4%1tTn2YO5Od(0DII9_JkBuDnE26(}w@ThU3MCBMb9|nWcro-tn=rOd+r~ zHZd?%bVr?*-QyH+5-O$C0)8;MnJwhtbquW_X06kSl9qaikf8K+A&sdEI~dsmT$UKp&`x(f z0|{8&=p0^UrWEOsczqDzO(ttjjmi4R)^i$zMRxPE0iy(qtR(H|uzTegf90pqjZ z1;JT9c0?2+HNuVsOuP6wSr2ZuFLe^pKhBT>W{)%Y`pUxm>G~J1L&ouBtjsO63M-du zbv?l_LgH!oxmSASHQl4C zfxnv@N2E?DD!BAxhKLhY%1Rk}12_n`9hKH-N z#^efy9I)`wIcB8<$=m{__R~IIQ7er$N~2|Wrr`xt^eBj;<&6FwsS&mnFpQAtc~o&= zqP|a}W7`a|$2=xy{uC*ax*b#$(MPt*je2EQv0QU!8DM}f)e#$`7+Gh7m5R2MB@(>b zonuG=PH^YTQz>%pNRGE?xTulsb2rZED3O;U=T6{YWYy)x=8^WCoW*^f!32z~nFhY# zb;vj$44J*86J(HZR+lA4nLpKscMgdrKcXFJ=9`Vy|2%2;uOiKFy5hsqN z_Wu_d69Sq=NB02cv;C<0Qh zXc%(P@B-RJmk^2S%An4{1@7i=v%v zkz>-4j~HT~EmEY&83hL|MO&0KlR|mS?KGHxM;U+JdkpY>ycj_xfH1Mq{1e?cSdc^Y zYNbouT?}rA{8r9$Oo=Ek_1TLOyGyivFRD%qPL0zRF=m({MN|b}zKj@I<7A=Rz*14; zz|zvewksP}z+207Jc$%Z6_D`Oq9J$NpyX{%7))OdHG)m*+ll6hY zv7)OQ)_L+Ab^yziT5m*E8rXt0bp<$y52`^Ww;{#<0SnAxqZs4VSI0co@4_(!1 z%Oq?;FhjEOv30t@Tp_pH-~)UbYWT`y1WDWjBEq$CGW_^pqa;bWa=6jh!1#b32f5e4 zcgpYQJos2n>G7vdaT>A@hF~s)S||$%OLBGJC59W|-e>Btmm%SlO_u zppRca_IECEOTZl?ICKvUY!Z_V;ut4oO=x-J#7rlXl_T*o5Va?7Ei7wSz9N6Y^1m~@ z02dWsRSn;j^HZcqWE;rLt1FFE+={{V_v%E6m{nllp4$2OZrO0-4jJ7490G?b(T9OX z&+6w1{$w|JR&960aLeH3!S5MEJxn`!ArN8+V1*Z_W;A{ ztHnTxmTBJCBGDE1jM;UTJtV2|^(4A@oJ{mxHb%;k-#9JM6k1?Dx z#cK+z}nJnT+F}V%R(6 z*K%H6qM|h=`AAW6pDNnwPA#+#O}mxC*e=;|fY{B`3^btMj3kt3DS zyXXA>+qRvyJr}m2-;j03i2;cV54-0Xd_cdETD0^clz%?t)eFP&Y;zjE^tPEboP7TR zg9)f^y0WX4P5+jbBk+X)VzPh^#BaUCMyi^7k--HxeUwllKaA+ctQvVQ1`n}bKf;X+ zHO|_)ZJT?Ep#}7ec4&*F2zn_%>2@?Sw6p47W;lJdBPbE`a$ry&q6H91v3iAJ1T0H* zu6|VNB)k%YC44$n5-R8tPe zexIRim4D8u>M5r>QX$~|BBq^s)RtsVaP{IL_W{GWV?Lv^Ie9ITJ_r)#Ve;}SjjEh) zGq%rt$Z)phb5ie~GDLhB2vp~2F|k-3Xvh?7yzV|?H~~Xqmj%gKkHC)-$RT7>7G$t0 z>^^3IAwxbQA5mVH{#61CksNs+2QO8tNuLHuofyB3S5og9bIXU$ai1})fCt!RS1{#>`z&x65|PO|v1?Q={;3v+ z>JY(|Z|&x3bU;n}FwXt6%DbD$bsW%dQb9+hvb)1(6eR~cB-grB?4tlT$gqVjuwzH4}QssFC+o z@UAC3U%7A&j8@OD8Q8hYLaf_JY#l?+aV& zTzP4wglqN|T5>bNjQfH7{5F?fE)DC_d&wVr1N1pSyGKZK1+etTVFhCeZ&fZE+L6N~%jg zvEol6Sl7#*mQ1ppyX~P8xZd4n!l5BbXjUfiSM^*5THKRq; zZ-Kf7P||TAAIAO8Kmt7YOiuw3s{bD9v71=jt7p~y!2mYuCVCkn{s_d$M@a#q!~6Vy z8<{it{$!A&^7}cjigNzht*=cx{tP=#5?wzEjkZ?gmLU_G{fjZ9pU`YKVcPIl*pTjL zB(+8QnZFrqU;T_q5%hO}Fq4r%P_nP9lX6t$KMZB7{BzDTP7R@v3IYEF05i*m3?5Uf zv$BT$FQXq&`Az2>YmxGAP|&!e>A{#>;#L_OlRne^$It?Xf-ZB6M3Bh;0*Qjjl7+Me zWak`pv+Sr7(BM+*9bSa;R}!ss%J@#1%5t02l?^ALNS)KblpvW`0W&p^k+Tk^R97{$ zfJ)a%Qz>$;2F|ha=&bv#8!O$_4X}rY6X15MCdo&GjC$e+o_NPWW2?J{p>EVCPVG5p zY$flS;6>f$L}R!pdkuEFYZ=nUx=qRuacv+{Q?;6$A}aIvad#bq>2In=IpVGh+>P-B z{r0bBdwOoJ!A)S-Gt3^Zj=p}R6FCgJ2`r;Y@bv*cQNSy5drkp=G}^1n%S*C=BqPMs zlHB!n149p3QB^TzuPaLfZU_TTL&?`&;PIgWcZ{*)F7lF=%i8>#(|7L+lT`!D!)$un?_M{4lwat1u>U6rBy9WQ^(Y zZrDO1313UIa>Shs9Qri|c(F}=PZh4_O$;!=iKmDX`5{&$^QK^;{_!^uRMxHGrx;|w z_(Y8il7b|j3L?fQaX0o%mg`kXFdBBJ8QOOFg`C!wa#vyoEUejjl)vUQI2X&vb+kf0`40u=m3ry+x zXPYE#N#<8ppT^u4#$e=1^_O~ZthAD1DLoT@*<@1Jq-L8acB*NM6^ldtu|yE-rCOktN@=l zRja%R<+noqbdg_w1jb?i1J%aXbKEuq9+&UsbPGX)a7>_8+hJ8|?lCY{m-zK)sV*B4 zjST@EVV4J;2oiZVkeIchPmxV`xZUd!GqZg!L&6WfU4RD8JA?3!O zqC5tbC47Lzjg}}Y6Ou<)o1B<%gN7U6;&e_JV>$AMz{40B@q~sHSvPEG0m}=Wv`CDs zB3LH~D}7u{VP;OeNttzEr|gKK1_Xd&Eu2FUe~@!%(!#W06c(UUiAyWT$=Btmhq~Ko z&;dS3w*pg-#1e=YrsC~SxM&2+-f~jKT?}&vp3Tb2@_Adf$jvAcZ(NfN3X6p$H@k&i zYb>KxDgKm*61)pw1TLo+B;Z(Bo^xY{7SNUX?<$Hi)E|d_s^UmWfF9adHk7_9P9#QF z1uS-(Sh87iIAm_ZpaS}uOy3+Uk#jLP*}i7b_cc|6>c6k?f+W^Jgg2IZM_>a$u5UEm>>+ng13ELm zDr8y}M5x|`y3W@%$3rGx;{(-QGB21ikbtmYhcgnZkv0t)=0!H7fRmk~u!3wVH0X)^ z@>xA?UiOD+2rX*CqT?fr^pLro_3^RPA#?kUF#$=D;6f@kqKhv1v*7CtI9}Wu9FTjg z4j6363>XT^OcvdsMbsQnXdY3m^K+t0HxBAjYgLP&g8*SfjmB`C_#%#m@2BStFJR)= zIf|zhNnK#^G!h^?8TXD>C)}dJg^WOmMfm54zeP&KECGY@K(mJ9!w4Id(y&`Luz()G zZezhYZSTx-)uqIHmHTN}0=Clu~uA1;mz z$SD{N-Irf?E5@JzUz|#62tQDIdk)nfd(|5&N}9`NIDFXZ>M^& zGR^@S9vO2-3@V_T?6Pw!QX^~)FszNgIXRslQHX`M_hVGhV-ydvUoJyv!dJokD3^SmMSZ_)UJ@Ot19^PfNs-$<7 z>;1qF>IbN+QBfDDe~|4Y@}dP{68lN89sK z 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

    {1#9XBU)#o?Wcn_t|6L60Oit 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�sF+=G4ZL+c!<)Ln4^1mtfIm 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 q-Ns@;Huq#iE8D;WbJ*t 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

    3Ll;k_w=Ck0A5yubi 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%0D1ZY30%T2hpGx>>m={!%5vEnYsbZOu@lF%63Ke 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

    k528Deq{dc&b=aexu&GnG|>jxg}HIS&=1J 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/html/.buildinfo b/doc/sphinx/_build/html/.buildinfo new file mode 100644 index 00000000..25f64894 --- /dev/null +++ b/doc/sphinx/_build/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: b80fe6905e1167a38cd1f4c456e3337c +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/doc/sphinx/_build/html/_layout/modules.html b/doc/sphinx/_build/html/_layout/modules.html new file mode 100644 index 00000000..40aa1401 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/modules.html @@ -0,0 +1,150 @@ + + + + + + + + nepi — NEPI 3.0 documentation + + + + + + + + + + + +

    +
    +
    +

    This Page

    + + + +
    +
    + + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.data.html b/doc/sphinx/_build/html/_layout/nepi.data.html new file mode 100644 index 00000000..5199c38f --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.data.html @@ -0,0 +1,134 @@ + + + + + + + + nepi.data package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.data.processing.ccn.html b/doc/sphinx/_build/html/_layout/nepi.data.processing.ccn.html new file mode 100644 index 00000000..49ad55d6 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.data.processing.ccn.html @@ -0,0 +1,174 @@ + + + + + + + + nepi.data.processing.ccn package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + +
    +
    +
    +
    + +
    +

    nepi.data.processing.ccn package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.data.processing.ccn.parser module¶

    +
    +
    +nepi.data.processing.ccn.parser.annotate_cn_graph(logs_dir, graph, parse_ping_logs=False)[source]¶
    +

    Adds CCN content history for each node in the topology graph.

    +
    + +
    +
    +nepi.data.processing.ccn.parser.annotate_cn_node(graph, nid, ips2nid, data, content_history)[source]¶
    +
    + +
    +
    +nepi.data.processing.ccn.parser.ccn_consumers(graph)[source]¶
    +

    Returns the nodes that are content consumers

    +
    + +
    +
    +nepi.data.processing.ccn.parser.ccn_producers(graph)[source]¶
    +

    Returns the nodes that are content providers

    +
    + +
    +
    +nepi.data.processing.ccn.parser.dump_content_history(content_history)[source]¶
    +
    + +
    +
    +nepi.data.processing.ccn.parser.is_control(content_name)[source]¶
    +
    + +
    +
    +nepi.data.processing.ccn.parser.load_content_history(fname)[source]¶
    +
    + +
    +
    +nepi.data.processing.ccn.parser.parse_file(filename)[source]¶
    +

    Parses message information from ccnd log files

    +

    filename: path to ccndlog file

    +
    + +
    +
    +nepi.data.processing.ccn.parser.process_content_history(graph)[source]¶
    +

    Compute CCN message counts and aggregates content historical +information in the content_names dictionary

    +
    + +
    +
    +nepi.data.processing.ccn.parser.process_content_history_logs(logs_dir, graph, parse_ping_logs=False)[source]¶
    +

    Parse CCN logs and aggregate content history information in graph. +Returns annotated graph and message countn and content names history.

    +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.data.processing.html b/doc/sphinx/_build/html/_layout/nepi.data.processing.html new file mode 100644 index 00000000..4fb2e10a --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.data.processing.html @@ -0,0 +1,127 @@ + + + + + + + + nepi.data.processing package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.data.processing.ping.html b/doc/sphinx/_build/html/_layout/nepi.data.processing.ping.html new file mode 100644 index 00000000..c9162d9c --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.data.processing.ping.html @@ -0,0 +1,133 @@ + + + + + + + + nepi.data.processing.ping package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + +
    +
    +
    +
    + +
    +

    nepi.data.processing.ping package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.data.processing.ping.parser module¶

    +
    +
    +nepi.data.processing.ping.parser.annotate_cn_graph(logs_dir, graph)[source]¶
    +

    Add delay inormation to graph using data collected using +ping.

    +
    + +
    +
    +nepi.data.processing.ping.parser.annotate_cn_node(graph, nid1, ips2nid, data)[source]¶
    +
    + +
    +
    +nepi.data.processing.ping.parser.parse_file(filename)[source]¶
    +

    filename: path to traceroute file

    +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.execution.html b/doc/sphinx/_build/html/_layout/nepi.execution.html new file mode 100644 index 00000000..75b38a02 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.execution.html @@ -0,0 +1,2376 @@ + + + + + + + + nepi.execution package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +

    nepi.execution package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.execution.attribute module¶

    +
    +
    +class nepi.execution.attribute.Attribute(name, help, type='STRING', flags=None, default=None, allowed=None, range=None, set_hook=None)[source]¶
    +

    Bases: object

    +

    An Attribute exposes a configuration parameter of a resource

    +
    +
    +allowed[source]¶
    +

    Returns the set of allowed values for the Attribute

    +
    + +
    +
    +default[source]¶
    +

    Returns the default value of the Attribute

    +
    + +
    +
    +flags[source]¶
    +

    Returns the flags of the Attribute

    +
    + +
    +
    +get_value()[source]¶
    +

    Returns the value of the Attribute

    +
    + +
    +
    +has_changed[source]¶
    +

    Returns True if the value has changed from the default

    +
    + +
    +
    +has_flag(flag)[source]¶
    +

    Returns True if the Attribute has the flag ‘flag’

    + +++ + + + +
    Parameters:flag (Flags) – Flag to be checked
    +
    + +
    +
    +help[source]¶
    +

    Returns the description of the Attribute

    +
    + +
    +
    +is_valid_value(value)[source]¶
    +

    Attribute subclasses will override this method to add +adequate validation

    +
    + +
    +
    +name[source]¶
    +

    Returns the name of the Attribute

    +
    + +
    +
    +range[source]¶
    +

    Returns the range of allowed numerical values for the Attribute

    +
    + +
    +
    +set_value(value)[source]¶
    +

    Configure a new value for the Attribute

    +
    + +
    +
    +type[source]¶
    +

    Returns the type of the Attribute

    +
    + +
    +
    +value¶
    +

    Returns the value of the Attribute

    +
    + +
    + +
    +
    +class nepi.execution.attribute.Flags[source]¶
    +

    Flags to characterize the scope of an Attribute

    +
    +
    +Construct = 8¶
    +
    + +
    +
    +Credential = 20¶
    +
    + +
    +
    +Design = 4¶
    +
    + +
    +
    +Filter = 36¶
    +
    + +
    +
    +Global = 128¶
    +
    + +
    +
    +NoRead = 1¶
    +
    + +
    +
    +NoWrite = 2¶
    +
    + +
    +
    +Reserved = 64¶
    +
    + +
    + +
    +
    +class nepi.execution.attribute.Types[source]¶
    +

    Allowed types for the Attribute value

    +
    +
    +Bool = 'BOOL'¶
    +
    + +
    +
    +Double = 'DOUBLE'¶
    +
    + +
    +
    +Enumerate = 'ENUM'¶
    +
    + +
    +
    +Integer = 'INTEGER'¶
    +
    + +
    +
    +String = 'STRING'¶
    +
    + +
    + +
    +
    +

    nepi.execution.ec module¶

    +
    +
    +class nepi.execution.ec.ECState[source]¶
    +

    Bases: object

    +

    Possible states of the ExperimentController

    +
    +
    +FAILED = 2¶
    +
    + +
    +
    +RELEASED = 3¶
    +
    + +
    +
    +RUNNING = 1¶
    +
    + +
    +
    +TERMINATED = 4¶
    +
    + +
    + +
    +
    +class nepi.execution.ec.ExperimentController(exp_id=None, local_dir=None, persist=False, fm=None, add_node_callback=None, add_edge_callback=None, **kwargs)[source]¶
    +

    Bases: object

    +

    An experiment, or scenario, is defined by a concrete set of resources, +and the behavior, configuration and interconnection of those resources. +The Experiment Description (ED) is a detailed representation of a +single experiment. It contains all the necessary information to +allow repeating the experiment. NEPI allows to describe +experiments by registering components (resources), configuring them +and interconnecting them.

    +

    A same experiment (scenario) can be executed many times, generating +different results. We call an experiment execution (instance) a ‘run’.

    +

    The ExperimentController (EC), is the entity responsible of +managing an experiment run. The same scenario can be +recreated (and re-run) by instantiating an EC and recreating +the same experiment description.

    +

    An experiment is represented as a graph of interconnected +resources. A resource is a generic concept in the sense that any +component taking part of an experiment, whether physical of +virtual, is considered a resource. A resources could be a host, +a virtual machine, an application, a simulator, a IP address.

    +

    A ResourceManager (RM), is the entity responsible for managing a +single resource. ResourceManagers are specific to a resource +type (i.e. An RM to control a Linux application will not be +the same as the RM used to control a ns-3 simulation). +To support a new type of resource, a new RM must be implemented. +NEPI already provides a variety of RMs to control basic resources, +and new can be extended from the existing ones.

    +

    Through the EC interface the user can create ResourceManagers (RMs), +configure them and interconnect them, to describe an experiment. +Describing an experiment through the EC does not run the experiment. +Only when the ‘deploy()’ method is invoked on the EC, the EC will take +actions to transform the ‘described’ experiment into a ‘running’ experiment.

    +

    While the experiment is running, it is possible to continue to +create/configure/connect RMs, and to deploy them to involve new +resources in the experiment (this is known as ‘interactive’ deployment).

    +

    An experiments in NEPI is identified by a string id, +which is either given by the user, or automatically generated by NEPI. +The purpose of this identifier is to separate files and results that +belong to different experiment scenarios. +However, since a same ‘experiment’ can be run many times, the experiment +id is not enough to identify an experiment instance (run). +For this reason, the ExperimentController has two identifier, the +exp_id, which can be re-used in different ExperimentController, +and the run_id, which is unique to one ExperimentController instance, and +is automatically generated by NEPI.

    +
    +
    +abort[source]¶
    +

    Returns True if the experiment has failed and should be interrupted, +False otherwise.

    +
    + +
    +
    +deploy(guids=None, wait_all_ready=True, group=None)[source]¶
    +

    Deploys all ResourceManagers in the guids list.

    +

    If the argument ‘guids’ is not given, all RMs with state NEW +are deployed.

    +
    +
    +++ + + + + + + + + + + + + + + +
    param guids:List of guids of RMs to deploy
    type guids:list
    param wait_all_ready:
     Wait until all RMs are ready in +order to start the RMs
    type guid:int
    param group:Id of deployment group in which to deploy RMs
    type group:int
    +
    +
    + +
    +
    +discover(guid)[source]¶
    +

    Discovers an available resource matching the criteria defined +by the RM with guid ‘guid’, and associates that resource to the RM

    +

    Not all RM types require (or are capable of) performing resource +discovery. For the RM types which are not capable of doing so, +invoking this method does not have any consequences.

    +
    +
    +++ + + + + + +
    param guid:Guid of the RM
    type guid:int
    +
    +
    + +
    +
    +ecstate[source]¶
    +

    Returns the state of the Experiment Controller

    +
    + +
    +
    +enable_trace(guid, name)[source]¶
    +

    Enables a trace to be collected during the experiment run

    + +++ + + + +
    Parameters:name (str) – Name of the trace
    +
    + +
    +
    +exp_dir[source]¶
    +

    Local directory to store results and other files related to the +experiment.

    +
    + +
    +
    +exp_id[source]¶
    +

    Returns the experiment id assigned by the user

    +
    + +
    +
    +failure_level[source]¶
    +

    Returns the level of FAILURE of th experiment

    +
    + +
    +
    +filter_resources(rtype)[source]¶
    +

    Returns the guids of all ResourceManagers of type rtype

    + +++ + + + + + +
    Parameters:rtype (string) – Resource type
    Return type:list of guids
    +
    + +
    +
    +fm[source]¶
    +

    Returns the failure manager

    +
    + +
    +
    +get(guid, name)[source]¶
    +

    Returns the value of the attribute with name ‘name’ on the +RM with guid ‘guid’

    +
    +
    +++ + + + + + + + + + + + +
    param guid:Guid of the RM
    type guid:int
    param name:Name of the attribute
    type name:str
    return:The value of the attribute with name ‘name’
    +
    +
    + +
    +
    +get_attribute(guid, name)[source]¶
    +

    Returns the attribute ‘name’ of the RM with guid ‘guid’

    + +++ + + + + + + + +
    Parameters:
      +
    • guid (int) – Guid of the RM
    • +
    • name (str) – Name of the attribute
    • +
    +
    Returns:

    The attribute with name ‘name’

    +
    Return type:

    Attribute

    +
    +
    + +
    +
    +get_attributes(guid)[source]¶
    +

    Returns all the attributes of the RM with guid ‘guid’

    + +++ + + + + + + + +
    Parameters:guid (int) – Guid of the RM
    Returns:List of attributes
    Return type:list
    +
    + +
    +
    +get_discover_time(guid)[source]¶
    +

    Returns the discover time of the RM as a timestamp

    +
    + +
    +
    +get_failed_time(guid)[source]¶
    +

    Returns the time failure occured for the RM as a timestamp

    +
    + +
    +
    +get_global(rtype, name)[source]¶
    +

    Returns the value of the global attribute with name ‘name’ on the +RMs of rtype ‘rtype’.

    +
    +
    +++ + + + + + + + + + + + +
    param guid:Guid of the RM
    type guid:int
    param name:Name of the attribute
    type name:str
    return:The value of the attribute with name ‘name’
    +
    +
    + +
    +
    +get_provision_time(guid)[source]¶
    +

    Returns the provision time of the RM as a timestamp

    +
    + +
    +
    +get_ready_time(guid)[source]¶
    +

    Returns the deployment time of the RM as a timestamp

    +
    + +
    +
    +get_release_time(guid)[source]¶
    +

    Returns the release time of the RM as a timestamp

    +
    + +
    +
    +get_resource(guid)[source]¶
    +

    Returns a registered ResourceManager by its guid

    + +++ + + + + + +
    Parameters:guid (int) – Id of the resource
    Return type:ResourceManager
    +
    + +
    +
    +get_resources_by_type(rtype)[source]¶
    +

    Returns the ResourceManager objects of type rtype

    + +++ + + + + + +
    Parameters:rtype (string) – Resource type
    Return type:list of ResourceManagers
    +
    + +
    +
    +get_start_time(guid)[source]¶
    +

    Returns the start time of the RM as a timestamp

    +
    + +
    +
    +get_stop_time(guid)[source]¶
    +

    Returns the stop time of the RM as a timestamp

    +
    + +
    +
    +get_task(tid)[source]¶
    +

    Returns a task by its id

    + +++ + + + + + +
    Parameters:tid (int) – Id of the task
    Return type:Task
    +
    + +
    +
    +get_traces(guid)[source]¶
    +

    Returns the list of the trace names of the RM with guid ‘guid’

    + +++ + + + + + + + +
    Parameters:guid (int) – Guid of the RM
    Returns:List of trace names
    Return type:list
    +
    + +
    +
    +inform_failure(guid)[source]¶
    +

    Reports a failure in a RM to the EC for evaluation

    + +++ + + + +
    Parameters:guid (int) – Resource id
    +
    + +
    +
    +classmethod load(filepath, format='xml')[source]¶
    +
    + +
    +
    +local_dir[source]¶
    +

    Root local directory for experiment files

    +
    + +
    +
    +logger[source]¶
    +

    Returns the logger instance of the Experiment Controller

    +
    + +
    +
    +netgraph[source]¶
    +

    Return NetGraph instance if experiment description was automatically +generated

    +
    + +
    +
    +nthreads[source]¶
    +

    Returns the number of processing nthreads used

    +
    + +
    +
    +persist[source]¶
    +

    If True, persists the ExperimentController to XML format upon +experiment completion

    +
    + +
    +
    +plot(dirpath=None, format='figure', show=False)[source]¶
    +
    + +
    +
    +provision(guid)[source]¶
    +

    Provisions the resource associated to the RM with guid ‘guid’.

    +

    Provisioning means making a resource ‘accessible’ to the user. +Not all RM types require (or are capable of) performing resource +provisioning. For the RM types which are not capable of doing so, +invoking this method does not have any consequences.

    +
    +
    +++ + + + + + +
    param guid:Guid of the RM
    type guid:int
    +
    +
    + +
    +
    +register_condition(guids1, action, guids2, state, time=None)[source]¶
    +

    Registers an action START, STOP or DEPLOY for all RM on list +guids1 to occur at time ‘time’ after all elements in list guids2 +have reached state ‘state’.

    +
    +
    +++ + + + + + + + + + + + + + + + + + + + + + +
    param guids1:List of guids of RMs subjected to action
    type guids1:list
    param action:Action to perform (either START, STOP or DEPLOY)
    type action:ResourceAction
    param guids2:List of guids of RMs to we waited for
    type guids2:list
    param state:State to wait for on RMs of list guids2 (STARTED, +STOPPED, etc)
    type state:ResourceState
    param time:Time to wait after guids2 has reached status
    type time:string
    +
    +
    + +
    +
    +register_connection(guid1, guid2)[source]¶
    +

    Registers a connection between a RM with guid ‘guid1’ +and another RM with guid ‘guid2’.

    +

    The order of the in which the two guids are provided is not +important, since the connection relationship is symmetric.

    +
    +
    +++ + + + + + + + + + +
    param guid1:First guid to connect
    type guid1:ResourceManager
    param guid2:Second guid to connect
    type guid:ResourceManager
    +
    +
    + +
    +
    +register_resource(rtype, guid=None)[source]¶
    +

    Registers a new ResourceManager of type ‘rtype’ in the experiment

    +

    This method will assign a new ‘guid’ for the RM, if no guid +is specified.

    +
    +
    +++ + + + + + + + + + +
    param rtype:Type of the RM
    type rtype:str
    return:Guid of the RM
    rtype:int
    +
    +
    + +
    +
    +release(guids=None)[source]¶
    +

    Releases all ResourceManagers in the guids list.

    +

    If the argument ‘guids’ is not given, all RMs registered +in the experiment are released.

    +
    +
    +++ + + + + + +
    param guids:List of RM guids
    type guids:list
    +
    +
    + +
    +
    +remove_resource(guid)[source]¶
    +
    + +
    +
    +resources[source]¶
    +

    Returns the guids of all ResourceManagers

    + +++ + + + + + +
    Returns:Set of all RM guids
    Return type:list
    +
    + +
    +
    +run_dir[source]¶
    +

    Local directory to store results and other files related to the +experiment run.

    +
    + +
    +
    +run_id[source]¶
    +

    Returns the experiment instance (run) identifier (automatically +generated)

    +
    + +
    +
    +save(dirpath=None, format='xml')[source]¶
    +
    + +
    +
    +schedule(date, callback, track=False)[source]¶
    +

    Schedules a callback to be executed at time ‘date’.

    + +++ + + + +
    Parameters:
      +
    • date – string containing execution time for the task. +It can be expressed as an absolute time, using +timestamp format, or as a relative time matching +^d+.d+(h|m|s|ms|us)$
    • +
    • callback – code to be executed for the task. Must be a +Python function, and receives args and kwargs +as arguments.
    • +
    • track – if set to True, the task will be retrievable with +the get_task() method
    • +
    +
    +

    :return : The Id of the task +:rtype: int

    +
    + +
    +
    +serialize(format='xml')[source]¶
    +
    + +
    +
    +set(guid, name, value)[source]¶
    +

    Modifies the value of the attribute with name ‘name’ on the +RM with guid ‘guid’.

    +
    +
    +++ + + + + + + + + + + + +
    param guid:Guid of the RM
    type guid:int
    param name:Name of the attribute
    type name:str
    param value:Value of the attribute
    +
    +
    + +
    +
    +set_global(rtype, name, value)[source]¶
    +

    Modifies the value of the global attribute with name ‘name’ on the +RMs of with rtype ‘rtype’.

    +
    +
    +++ + + + + + + + + + + + +
    param guid:Guid of the RM
    type guid:int
    param name:Name of the attribute
    type name:str
    param value:Value of the attribute
    +
    +
    + +
    +
    +set_with_conditions(name, value, guids1, guids2, state, time=None)[source]¶
    +

    Modifies the value of attribute with name ‘name’ on all RMs +on the guids1 list when time ‘time’ has elapsed since all +elements in guids2 list have reached state ‘state’.

    +
    +
    +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    param name:Name of attribute to set in RM
    type name:string
    param value:Value of attribute to set in RM
    type name:string
    param guids1:List of guids of RMs subjected to action
    type guids1:list
    param action:Action to register (either START or STOP)
    type action:ResourceAction
    param guids2:List of guids of RMs to we waited for
    type guids2:list
    param state:State to wait for on RMs (STARTED, STOPPED, etc)
    type state:ResourceState
    param time:Time to wait after guids2 has reached status
    type time:string
    +
    +
    + +
    +
    +shutdown()[source]¶
    +

    Releases all resources and stops the ExperimentController

    +
    + +
    +
    +start(guid)[source]¶
    +

    Starts the RM with guid ‘guid’

    +

    Starting a RM means that the resource it controls will +begin taking part of the experiment.

    +
    +
    +++ + + + + + +
    param guid:Guid of the RM
    type guid:int
    +
    +
    + +
    +
    +state(guid, hr=False)[source]¶
    +

    Returns the state of a resource

    + +++ + + + +
    Parameters:
      +
    • guid (integer) – Resource guid
    • +
    • hr (boolean) – Human readable. Forces return of a +status string instead of a number
    • +
    +
    +
    + +
    +
    +stop(guid)[source]¶
    +

    Stops the RM with guid ‘guid’

    +

    Stopping a RM means that the resource it controls will +no longer take part of the experiment.

    +
    +
    +++ + + + + + +
    param guid:Guid of the RM
    type guid:int
    +
    +
    + +
    +
    +trace(guid, name, attr='all', block=512, offset=0)[source]¶
    +

    Returns information on a collected trace, the trace stream or +blocks (chunks) of the trace stream

    +
    +
    +++ + + + + + + + + + + + + + + + + + + + +
    param name:

    Name of the trace

    +
    type name:

    str

    +
    param attr:

    Can be one of: +- TraceAttr.ALL (complete trace content), +- TraceAttr.STREAM (block in bytes to read starting

    +
    +

    at offset),

    +
    +
      +
    • TraceAttr.PATH (full path to the trace file),
    • +
    • TraceAttr.SIZE (size of trace file).
    • +
    +
    type attr:

    str

    +
    param block:

    Number of bytes to retrieve from trace, when attr is +TraceAttr.STREAM

    +
    type name:

    int

    +
    param offset:

    Number of ‘blocks’ to skip, when attr is TraceAttr.STREAM

    +
    type name:

    int

    +
    rtype:

    str

    +
    +
    +
    + +
    +
    +trace_enabled(guid, name)[source]¶
    +

    Returns True if the trace of name ‘name’ is enabled

    + +++ + + + +
    Parameters:name (str) – Name of the trace
    +
    + +
    +
    +wait(guids, state, quit)[source]¶
    +

    Blocking method that waits until all RMs in the ‘guids’ list +have reached a state >= ‘state’, or until the ‘quit’ callback +yields True

    +
    +
    +++ + + + + + +
    param guids:List of guids
    type guids:list
    +
    +
    + +
    +
    +wait_deployed(guids)[source]¶
    +

    Blocking method that waits until all RMs in the ‘guids’ list +have reached a state >= READY, or until a failure in the +experiment occurs (i.e. abort == True)

    +
    +
    +++ + + + + + +
    param guids:List of guids
    type guids:list
    +
    +
    + +
    +
    +wait_finished(guids)[source]¶
    +

    Blocking method that waits until all RMs in the ‘guids’ list +have reached a state >= STOPPED (i.e. STOPPED, FAILED or +RELEASED ), or until a failure in the experiment occurs +(i.e. abort == True)

    +
    +
    +++ + + + + + +
    param guids:List of guids
    type guids:list
    +
    +
    + +
    +
    +wait_released(guids)[source]¶
    +

    Blocking method that waits until all RMs in the ‘guids’ list +have reached a state == RELEASED, or until the EC fails

    +
    +
    +++ + + + + + +
    param guids:List of guids
    type guids:list
    +
    +
    + +
    +
    +wait_started(guids)[source]¶
    +

    Blocking method that waits until all RMs in the ‘guids’ list +have reached a state >= STARTED, or until a failure in the +experiment occurs (i.e. abort == True)

    +
    +
    +++ + + + + + +
    param guids:List of guids
    type guids:list
    +
    +
    + +
    + +
    +
    +class nepi.execution.ec.FailureLevel[source]¶
    +

    Bases: object

    +

    Possible failure states for the experiment

    +
    +
    +EC_FAILURE = 3¶
    +
    + +
    +
    +OK = 1¶
    +
    + +
    +
    +RM_FAILURE = 2¶
    +
    + +
    + +
    +
    +class nepi.execution.ec.FailureManager[source]¶
    +

    Bases: object

    +

    The FailureManager is responsible for handling errors +and deciding whether an experiment should be aborted or not

    +
    +
    +abort[source]¶
    +
    + +
    +
    +ec[source]¶
    +

    Returns the ExperimentController associated to this FailureManager

    +
    + +
    +
    +eval_failure(guid)[source]¶
    +

    Implements failure policy and sets the abort state of the +experiment based on the failure state and criticality of +the RM

    + +++ + + + +
    Parameters:guid (int) – Guid of the RM upon which the failure of the experiment +is evaluated
    +
    + +
    +
    +set_ec(ec)[source]¶
    +
    + +
    +
    +set_ec_failure()[source]¶
    +
    + +
    + +
    +
    +

    nepi.execution.resource module¶

    +
    +
    +class nepi.execution.resource.ResourceAction[source]¶
    +

    Action that a user can order to a Resource Manager

    +
    +
    +DEPLOY = 0¶
    +
    + +
    +
    +START = 1¶
    +
    + +
    +
    +STOP = 2¶
    +
    + +
    + +
    +
    +class nepi.execution.resource.ResourceFactory[source]¶
    +

    Bases: object

    +
    +
    +classmethod create(rtype, ec, guid)[source]¶
    +

    Create a new instance of a Ressource Manager

    +
    + +
    +
    +classmethod get_resource_type(rtype)[source]¶
    +

    Return the type of the Class

    +
    + +
    +
    +classmethod register_type(rclass)[source]¶
    +

    Register a new Ressource Manager

    +
    + +
    +
    +classmethod resource_types()[source]¶
    +

    Return the type of the Class

    +
    + +
    + +
    +
    +class nepi.execution.resource.ResourceManager(ec, guid)[source]¶
    +

    Bases: nepi.util.logger.Logger

    +

    Base clase for all ResourceManagers.

    +

    A ResourceManger is specific to a resource type (e.g. Node, +Switch, Application, etc) on a specific platform (e.g. PlanetLab, +OMF, etc).

    +

    The ResourceManager instances are responsible for interacting with +and controlling concrete (physical or virtual) resources in the +experimental platforms.

    +
    +
    +conditions[source]¶
    +

    Returns the conditions to which the RM is subjected to.

    +

    This method returns a dictionary of conditions lists indexed by +a ResourceAction.

    +
    + +
    +
    +configure(*args, **kwargs)[source]¶
    +
    + +
    +
    +connections[source]¶
    +

    Returns the set of guids of connected RMs

    +
    + +
    +
    +deploy(*args, **kwargs)[source]¶
    +
    + +
    +
    +deploy_with_conditions()[source]¶
    +

    Deploy RM when all the conditions in self.conditions for +action ‘READY’ are satisfied.

    +
    + +
    +
    +discover(*args, **kwargs)[source]¶
    +
    + +
    +
    +discover_time[source]¶
    +

    Returns the discover time of the RM as a timestamp

    +
    + +
    +
    +do_configure()[source]¶
    +
    + +
    +
    +do_connect(guid)[source]¶
    +

    Performs actions that need to be taken upon associating RMs. +This method should be redefined when necessary in child classes.

    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_disconnect(guid)[source]¶
    +

    Performs actions that need to be taken upon disassociating RMs. +This method should be redefined when necessary in child classes.

    +
    + +
    +
    +do_discover()[source]¶
    +
    + +
    +
    +do_fail()[source]¶
    +
    + +
    +
    +do_provision()[source]¶
    +
    + +
    +
    +do_release()[source]¶
    +
    + +
    +
    +do_reserve()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +do_stop()[source]¶
    +
    + +
    +
    +ec[source]¶
    +

    Returns the Experiment Controller of the RM

    +
    + +
    +
    +enable_trace(name)[source]¶
    +

    Explicitly enable trace generation

    + +++ + + + +
    Parameters:name (str) – Name of the trace
    +
    + +
    +
    +fail()[source]¶
    +

    Sets the RM to state FAILED.

    +

    This method should not be overridden directly. Specific functionality +should be added in the do_fail method.

    +
    + +
    +
    +failed_time[source]¶
    +

    Returns the time failure occurred for the RM as a timestamp

    +
    + +
    +
    +get(name)[source]¶
    +

    Returns the value of the attribute

    + +++ + + + + + +
    Parameters:name (str) – Name of the attribute
    Return type:str
    +
    + +
    +
    +classmethod get_attribute(name)[source]¶
    +

    Returns a copy of the attribute with name ‘name’

    +
    + +
    +
    +classmethod get_attributes()[source]¶
    +

    Returns a copy of the attributes

    +
    + +
    +
    +get_connected(rtype=None)[source]¶
    +

    Returns the list of RM with the type ‘rtype’

    + +++ + + + + + +
    Parameters:rtype (str) – Type of the RM we look for
    Returns:list of guid
    +
    + +
    +
    +classmethod get_global(name)[source]¶
    +
    +
    Returns the value of a global attribute
    +
    Global attribute meaning an attribute for +all the resources from a rtype
    +
    + +++ + + + + + +
    Parameters:name (str) – Name of the attribute
    Return type:str
    +
    + +
    +
    +classmethod get_help()[source]¶
    +

    Returns the description of the type of Resource

    +
    + +
    +
    +classmethod get_platform()[source]¶
    +

    Returns the identified of the platform (i.e. testbed type) +for the Resource

    +
    + +
    +
    +classmethod get_rtype()[source]¶
    +

    Returns the type of the Resource Manager

    +
    + +
    +
    +classmethod get_traces()[source]¶
    +

    Returns a copy of the traces

    +
    + +
    +
    +guid[source]¶
    +

    Returns the global unique identifier of the RM

    +
    + +
    +
    +has_attribute(name)[source]¶
    +

    Returns true if the RM has an attribute with name

    + +++ + + + +
    Parameters:name (string) – name of the attribute
    +
    + +
    +
    +has_changed(name)[source]¶
    +
    +
    Returns the True is the value of the attribute
    +
    has been modified by the user.
    +
    + +++ + + + + + +
    Parameters:name (str) – Name of the attribute
    Return type:str
    +
    + +
    +
    +has_flag(name, flag)[source]¶
    +

    Returns true if the attribute has the flag ‘flag’

    + +++ + + + +
    Parameters:flag (Flags) – Flag to be checked
    +
    + +
    +
    +is_rm_instance(rtype)[source]¶
    +

    Returns True if the RM is instance of ‘rtype’

    + +++ + + + + + +
    Parameters:rtype (str) – Type of the RM we look for
    Returns:True|False
    +
    + +
    +
    +log_message(msg)[source]¶
    +

    Returns the log message formatted with added information.

    + +++ + + + + + +
    Parameters:msg (str) – text message
    Return type:str
    +
    + +
    +
    +provision(*args, **kwargs)[source]¶
    +
    + +
    +
    +provision_time[source]¶
    +

    Returns the provision time of the RM as a timestamp

    +
    + +
    +
    +ready_time[source]¶
    +

    Returns the deployment time of the RM as a timestamp

    +
    + +
    +
    +register_condition(action, group, state, time=None)[source]¶
    +

    Registers a condition on the resource manager to allow execution +of ‘action’ only after ‘time’ has elapsed from the moment all resources +in ‘group’ reached state ‘state’

    + +++ + + + +
    Parameters:
      +
    • action (str) – Action to restrict to condition (either ‘START’ or ‘STOP’)
    • +
    • group (int or list of int) – Group of RMs to wait for (list of guids)
    • +
    • state (str) – State to wait for on all RM in group. (either ‘STARTED’, ‘STOPPED’ or ‘READY’)
    • +
    • time (str) – Time to wait after ‘state’ is reached on all RMs in group. (e.g. ‘2s’)
    • +
    +
    +
    + +
    +
    +register_connection(guid)[source]¶
    +

    Registers a connection to the RM identified by guid

    +

    This method should not be overridden. Specific functionality +should be added in the do_connect method.

    + +++ + + + +
    Parameters:guid (int) – Global unique identified of the RM to connect to
    +
    + +
    +
    +release()[source]¶
    +

    Perform actions to free resources used by the RM.

    +

    This method is responsible for releasing resources that were +used during the experiment by the RM.

    +

    This method should not be overridden directly. Specific functionality +should be added in the do_release method.

    +
    + +
    +
    +release_time[source]¶
    +

    Returns the release time of the RM as a timestamp

    +
    + +
    +
    +reschedule_delay[source]¶
    +

    Returns default reschedule delay

    +
    + +
    +
    +reserve(*args, **kwargs)[source]¶
    +
    + +
    +
    +reserved_time[source]¶
    +

    Returns the reserved time of the RM as a timestamp

    +
    + +
    +
    +set(name, value)[source]¶
    +

    Set the value of the attribute

    + +++ + + + +
    Parameters:
      +
    • name (str) – Name of the attribute
    • +
    • name – Value of the attribute
    • +
    +
    +
    + +
    +
    +set_discovered(time=None)[source]¶
    +

    Mark ResourceManager as DISCOVERED

    +
    + +
    +
    +set_failed(time=None)[source]¶
    +

    Mark ResourceManager as FAILED

    +
    + +
    +
    +classmethod set_global(name, value)[source]¶
    +

    Set value for a global attribute

    + +++ + + + +
    Parameters:
      +
    • name (str) – Name of the attribute
    • +
    • name – Value of the attribute
    • +
    +
    +
    + +
    +
    +set_provisioned(time=None)[source]¶
    +

    Mark ResourceManager as PROVISIONED

    +
    + +
    +
    +set_ready(time=None)[source]¶
    +

    Mark ResourceManager as READY

    +
    + +
    +
    +set_released(time=None)[source]¶
    +

    Mark ResourceManager as REALEASED

    +
    + +
    +
    +set_reserved(time=None)[source]¶
    +

    Mark ResourceManager as RESERVED

    +
    + +
    +
    +set_started(time=None)[source]¶
    +

    Mark ResourceManager as STARTED

    +
    + +
    +
    +set_state(state, state_time_attr, time=None)[source]¶
    +

    Set the state of the RM while keeping a trace of the time

    +
    + +
    +
    +set_state_time(state, state_time_attr, time)[source]¶
    +

    Set the time for the RM state change

    +
    + +
    +
    +set_stopped(time=None)[source]¶
    +

    Mark ResourceManager as STOPPED

    +
    + +
    +
    +set_with_conditions(name, value, group, state, time)[source]¶
    +

    Set value ‘value’ on attribute with name ‘name’ when ‘time’ +has elapsed since all elements in ‘group’ have reached state +‘state’

    + +++ + + + +
    Parameters:
      +
    • name (str) – Name of the attribute to set
    • +
    • name – Value of the attribute to set
    • +
    • group (int or list of int) – Group of RMs to wait for (list of guids)
    • +
    • state (str) – State to wait for on all RM in group. (either ‘STARTED’, ‘STOPPED’ or ‘READY’)
    • +
    • time (str) – Time to wait after ‘state’ is reached on all RMs in group. (e.g. ‘2s’)
    • +
    +
    +
    + +
    +
    +start(*args, **kwargs)[source]¶
    +
    + +
    +
    +start_time[source]¶
    +

    Returns the start time of the RM as a timestamp

    +
    + +
    +
    +start_with_conditions()[source]¶
    +

    Starts RM when all the conditions in self.conditions for +action ‘START’ are satisfied.

    +
    + +
    +
    +state[source]¶
    +

    Get the current state of the RM

    +
    + +
    +
    +stop(*args, **kwargs)[source]¶
    +
    + +
    +
    +stop_time[source]¶
    +

    Returns the stop time of the RM as a timestamp

    +
    + +
    +
    +stop_with_conditions()[source]¶
    +

    Stops RM when all the conditions in self.conditions for +action ‘STOP’ are satisfied.

    +
    + +
    +
    +trace(name, attr='all', block=512, offset=0)[source]¶
    +

    Get information on collected trace

    + +++ + + + + + +
    Parameters:
      +
    • name (int) – Name of the trace
    • +
    • attr (str) – Can be one of: +- TraceAttr.ALL (complete trace content), +- TraceAttr.STREAM (block in bytes to read starting at offset), +- TraceAttr.PATH (full path to the trace file), +- TraceAttr.SIZE (size of trace file).
    • +
    • block – Number of bytes to retrieve from trace, when attr is TraceAttr.STREAM
    • +
    • offset – Number of ‘blocks’ to skip, when attr is TraceAttr.STREAM
    • +
    +
    Return type:

    str

    +
    +
    + +
    +
    +trace_enabled(name)[source]¶
    +

    Returns True if trace is enables

    + +++ + + + +
    Parameters:name (str) – Name of the trace
    +
    + +
    +
    +unregister_condition(group, action=None)[source]¶
    +

    Removed conditions for a certain group of guids

    + +++ + + + +
    Parameters:
      +
    • action (str) – Action to restrict to condition (either ‘START’, ‘STOP’ or ‘READY’)
    • +
    • group (int or list of int) – Group of RMs to wait for (list of guids)
    • +
    +
    +
    + +
    +
    +unregister_connection(guid)[source]¶
    +

    Removes a registered connection to the RM identified by guid

    +

    This method should not be overridden. Specific functionality +should be added in the do_disconnect method.

    + +++ + + + +
    Parameters:guid (int) – Global unique identified of the RM to connect to
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +

    Checks whether a connection with the other RM +is valid. +This method need to be redefined by each new Resource Manager.

    + +++ + + + + + +
    Parameters:guid (int) – Guid of the current Resource Manager
    Return type:Boolean
    +
    + +
    + +
    +
    +class nepi.execution.resource.ResourceState[source]¶
    +

    State of a Resource Manager

    +
    +
    +DISCOVERED = 1¶
    +
    + +
    +
    +FAILED = 7¶
    +
    + +
    +
    +NEW = 0¶
    +
    + +
    +
    +PROVISIONED = 3¶
    +
    + +
    +
    +READY = 4¶
    +
    + +
    +
    +RELEASED = 8¶
    +
    + +
    +
    +RESERVED = 2¶
    +
    + +
    +
    +STARTED = 5¶
    +
    + +
    +
    +STOPPED = 6¶
    +
    + +
    + +
    +
    +nepi.execution.resource.clsinit(cls)[source]¶
    +

    Initializes template information (i.e. attributes and traces) +on classes derived from the ResourceManager class.

    +

    It is used as a decorator in the class declaration as follows:

    +
    +

    @clsinit +class MyResourceManager(ResourceManager):

    +
    +
    ...
    +
    +
    + +
    +
    +nepi.execution.resource.clsinit_copy(cls)[source]¶
    +

    Initializes template information (i.e. attributes and traces) +on classes derived from the ResourceManager class. +It differs from the clsinit method in that it forces inheritance +of attributes and traces from the parent class.

    +

    It is used as a decorator in the class declaration as follows:

    +
    +

    @clsinit +class MyResourceManager(ResourceManager):

    +
    +
    ...
    +
    +

    clsinit_copy should be prefered to clsinit when creating new +ResourceManager child classes.

    +
    + +
    +
    +nepi.execution.resource.failtrap(func)[source]¶
    +

    Decorator function for instance methods that should set the +RM state to FAILED when an error is raised. The methods that must be +decorated are: discover, reserved, provision, deploy, start, stop.

    +
    + +
    +
    +nepi.execution.resource.find_types()[source]¶
    +

    Look into the different folders to find all the +availables Resources Managers

    +
    + +
    +
    +nepi.execution.resource.populate_factory()[source]¶
    +

    Find and rgister all available RMs

    +
    + +
    +
    +

    nepi.execution.runner module¶

    +
    +
    +class nepi.execution.runner.ExperimentRunner[source]¶
    +

    Bases: object

    +

    The ExperimentRunner entity is responsible of +re-running an experiment described by an ExperimentController +multiple time

    +
    +
    +evaluate_normal_convergence(ec, run, metrics)[source]¶
    +

    Returns True when the confidence interval of the sample mean is +less than 5% of the mean value, for a 95% confidence level, +assuming normal distribution of the data

    +
    + +
    +
    +run(ec, min_runs=1, max_runs=-1, wait_time=0, wait_guids=[], compute_metric_callback=None, evaluate_convergence_callback=None)[source]¶
    +

    Run a same experiment independently multiple times, until the +evaluate_convergence_callback function returns True

    + +++ + + + +
    Parameters:
      +
    • ec (ExperimentController) – Description of experiment to replicate. +The runner takes care of deploying the EC, so ec.deploy() +must not be invoked directly before or after invoking +runner.run().
    • +
    • min_runs (int) – Minimum number of times the experiment must be +replicated
    • +
    • max_runs (int) – Maximum number of times the experiment can be +replicated
    • +
    • wait_time (float) – Time to wait in seconds on each run between invoking +ec.deploy() and ec.release().
    • +
    • wait_guids (list) – List of guids wait for finalization on each run. +This list is passed to ec.wait_finished()
    • +
    • compute_metric_callback (function) –

      User defined function invoked after +each experiment run to compute a metric. The metric is usually +a network measurement obtained from the data collected +during experiment execution. +The function is invoked passing the ec and the run number as arguments. +It must return the value for the computed metric(s) (usually a single +numerical value, but it can be several).

      +
      +
      metric = compute_metric_callback(ec, run)
      +
    • +
    • evaluate_convergence_callback (function) –

      User defined function invoked after +computing the metric on each run, to evaluate the experiment was +run enough times. It takes the list of cumulated metrics produced by +the compute_metric_callback up to the current run, and decided +whether the metrics have statistically converged to a meaningful value +or not. It must return either True or False.

      +
      +
      stop = evaluate_convergence_callback(ec, run, metrics)
      +

      If stop is True, then the runner will exit.

      +
    • +
    +
    +
    + +
    +
    +run_experiment(filepath, wait_time, wait_guids)[source]¶
    +

    Run an experiment based on the description stored +in filepath.

    +
    + +
    + +
    +
    +

    nepi.execution.scheduler module¶

    +
    +
    +class nepi.execution.scheduler.HeapScheduler[source]¶
    +

    Bases: object

    +

    Create a Heap Scheduler

    +
    +

    Note

    +

    This class is thread safe. +All calls to C Extensions are made atomic by the GIL in the CPython implementation. +heapq.heappush, heapq.heappop, and list access are therefore thread-safe.

    +
    +
    +
    +next()[source]¶
    +

    Get the next task in the queue by timestamp and arrival order

    +
    + +
    +
    +pending[source]¶
    +

    Returns the list of pending task ids

    +
    + +
    +
    +remove(tid)[source]¶
    +

    Remove a task form the queue

    + +++ + + + +
    Parameters:tid (int) – Id of the task to be removed
    +
    + +
    +
    +schedule(task)[source]¶
    +

    Add a task to the queue ordered by task.timestamp and arrival order

    + +++ + + + +
    Parameters:task (task) – task to schedule
    +
    + +
    + +
    +
    +class nepi.execution.scheduler.Task(timestamp, callback)[source]¶
    +

    Bases: object

    +

    A Task represents an operation to be executed by the +ExperimentController scheduler

    +
    + +
    +
    +class nepi.execution.scheduler.TaskStatus[source]¶
    +

    Execution state of the Task

    +
    +
    +DONE = 1¶
    +
    + +
    +
    +ERROR = 2¶
    +
    + +
    +
    +NEW = 0¶
    +
    + +
    + +
    +
    +

    nepi.execution.tags module¶

    +
    +
    +

    nepi.execution.trace module¶

    +
    +
    +class nepi.execution.trace.Trace(name, help, enabled=False)[source]¶
    +

    Bases: object

    +

    A Trace represents information about a Resource that can +be collected

    +
    +
    +help[source]¶
    +

    Returns the help of the trace

    +
    + +
    +
    +name[source]¶
    +

    Returns the name of the trace

    +
    + +
    + +
    +
    +class nepi.execution.trace.TraceAttr[source]¶
    +

    A Trace attribute defines information about a Trace that can +be queried

    +
    +
    +ALL = 'all'¶
    +
    + +
    +
    +PATH = 'path'¶
    +
    + +
    +
    +SIZE = 'size'¶
    +
    + +
    +
    +STREAM = 'stream'¶
    +
    + +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.html b/doc/sphinx/_build/html/_layout/nepi.html new file mode 100644 index 00000000..a68ddb6f --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.html @@ -0,0 +1,483 @@ + + + + + + + + nepi package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + +
    +
    +
    +
    + +
    +

    nepi package¶

    +
    +

    Subpackages¶

    +
    + +
    +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.all.html b/doc/sphinx/_build/html/_layout/nepi.resources.all.html new file mode 100644 index 00000000..ec59dd76 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.all.html @@ -0,0 +1,165 @@ + + + + + + + + nepi.resources.all package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + +
    +
    +
    +
    + +
    +

    nepi.resources.all package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.all.collector module¶

    +
    +
    +class nepi.resources.all.collector.Collector(ec, guid)[source]¶
    +

    Bases: nepi.execution.resource.ResourceManager

    +

    The collector entity is reponsible of collecting traces +of a same type associated to RMs into a local directory.

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • ec (ExperimentController) – The Experiment controller
    • +
    • guid (int) – guid of the RM
    • +
    +
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_provision()[source]¶
    +
    + +
    +
    +do_release()[source]¶
    +
    + +
    +
    +store_path[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.html b/doc/sphinx/_build/html/_layout/nepi.resources.html new file mode 100644 index 00000000..c7c70527 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.html @@ -0,0 +1,409 @@ + + + + + + + + nepi.resources package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + +
    +
    +
    +
    + +
    +

    nepi.resources package¶

    +
    +

    Subpackages¶

    +
    + +
    +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.linux.ccn.html b/doc/sphinx/_build/html/_layout/nepi.resources.linux.ccn.html new file mode 100644 index 00000000..82f66eeb --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.linux.ccn.html @@ -0,0 +1,446 @@ + + + + + + + + nepi.resources.linux.ccn package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +

    nepi.resources.linux.ccn package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.linux.ccn.ccnapplication module¶

    +
    +
    +class nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +ccnd[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.ccn.ccncat module¶

    +
    +
    +class nepi.resources.linux.ccn.ccncat.LinuxCCNCat(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.ccn.ccncontent module¶

    +
    +
    +class nepi.resources.linux.ccn.ccncontent.LinuxCCNContent(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +ccnd[source]¶
    +
    + +
    +
    +ccnr[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.ccn.ccnd module¶

    +
    +
    +class nepi.resources.linux.ccn.ccnd.LinuxCCND(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +do_stop()[source]¶
    +
    + +
    +
    +path[source]¶
    +
    + +
    +
    +state[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    +
    +version[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.ccn.ccnpeek module¶

    +
    +
    +class nepi.resources.linux.ccn.ccnpeek.LinuxCCNPeek(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.ccn.ccnping module¶

    +
    +
    +class nepi.resources.linux.ccn.ccnping.LinuxCCNPing(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ccn.ccnpingserver.LinuxCCNPingServer

    +
    +
    +ccnpingserver[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.ccn.ccnpingserver module¶

    +
    +
    +class nepi.resources.linux.ccn.ccnpingserver.LinuxCCNPingServer(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.ccn.ccnpoke module¶

    +
    +
    +class nepi.resources.linux.ccn.ccnpoke.LinuxCCNPoke(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.ccn.ccnr module¶

    +
    +
    +class nepi.resources.linux.ccn.ccnr.LinuxCCNR(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +ccnd[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.ccn.fibentry module¶

    +
    +
    +class nepi.resources.linux.ccn.fibentry.LinuxFIBEntry(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +ccnd[source]¶
    +
    + +
    +
    +configure()[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +do_stop()[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +ping[source]¶
    +
    + +
    +
    +trace(name, attr='all', block=512, offset=0)[source]¶
    +
    + +
    +
    +traceroute[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.linux.html b/doc/sphinx/_build/html/_layout/nepi.resources.linux.html new file mode 100644 index 00000000..08ed22a6 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.linux.html @@ -0,0 +1,1539 @@ + + + + + + + + nepi.resources.linux package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +

    nepi.resources.linux package¶

    +
    +

    Subpackages¶

    +
    + +
    +
    +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.linux.application module¶

    +
    +
    +class nepi.resources.linux.application.LinuxApplication(ec, guid)[source]¶
    +

    Bases: nepi.execution.resource.ResourceManager

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • ec (ExperimentController) – The Experiment controller
    • +
    • guid (int) – guid of the RM
    • +
    +
    +
    + +
    +

    Note

    +

    A LinuxApplication RM represents a process that can be executed in +a remote Linux host using SSH.

    +

    The LinuxApplication RM takes care of uploadin sources and any files +needed to run the experiment, to the remote host. +It also allows to provide source compilation (build) and installation +instructions, and takes care of automating the sources build and +installation tasks for the user.

    +

    It is important to note that files uploaded to the remote host have +two possible scopes: single-experiment or multi-experiment. +Single experiment files are those that will not be re-used by other +experiments. Multi-experiment files are those that will. +Sources and shared files are always made available to all experiments.

    +

    Directory structure:

    +

    The directory structure used by LinuxApplication RM at the Linux +host is the following:

    +
    +
    ${HOME}/.nepi/nepi-usr –> Base directory for multi-experiment files
    +
    +

    +
    +
    +
    +

    ${LIB} |- /lib –> Base directory for libraries +${BIN} |- /bin –> Base directory for binary files +${SRC} |- /src –> Base directory for sources +${SHARE} |- /share –> Base directory for other files

    +
    +
    ${HOME}/.nepi/nepi-exp –> Base directory for single-experiment files
    +
    +

    +
    +
    +
    ${EXP_HOME} |- /<exp-id> –> Base directory for experiment exp-id
    +
    +

    +
    +
    +
    ${APP_HOME} |- /<app-guid> –> Base directory for application
    +
    +
    specific files (e.g. command.sh, input)
    +

    +
    +
    +
    +

    ${RUN_HOME} |- /<run-id> –> Base directory for run specific

    +
    +
    +
    +app_home[source]¶
    +
    + +
    +
    +build(build=None)[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_provision()[source]¶
    +
    + +
    +
    +do_release()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +do_stop()[source]¶
    +

    Stops application execution

    +
    + +
    +
    +execute_command(command, env=None, sudo=False, tty=False, forward_x11=False, blocking=False)[source]¶
    +
    + +
    +
    +execute_deploy_command(command, prefix='deploy')[source]¶
    +
    + +
    +
    +in_foreground[source]¶
    +

    Returns True if the command needs to be executed in foreground. +This means that command will be executed using ‘execute’ instead of +‘run’ (‘run’ executes a command in background and detached from the +terminal)

    +

    When using X11 forwarding option, the command can not run in background +and detached from a terminal, since we need to keep the terminal attached +to interact with it.

    +
    + +
    +
    +install(install=None)[source]¶
    +
    + +
    +
    +install_dependencies(depends=None)[source]¶
    +
    + +
    +
    +log_message(msg)[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +pid[source]¶
    +
    + +
    +
    +ppid[source]¶
    +
    + +
    +
    +replace_paths(command, node=None, app_home=None, run_home=None)[source]¶
    +

    Replace all special path tags with shell-escaped actual paths.

    +
    + +
    +
    +run_home[source]¶
    +
    + +
    +
    +state[source]¶
    +

    Returns the state of the application

    +
    + +
    +
    +trace(name, attr='all', block=512, offset=0)[source]¶
    +
    + +
    +
    +trace_filepath(filename)[source]¶
    +
    + +
    +
    +upload_binaries(bins=None)[source]¶
    +
    + +
    +
    +upload_code(code=None)[source]¶
    +
    + +
    +
    +upload_files(files=None)[source]¶
    +
    + +
    +
    +upload_libraries(libs=None)[source]¶
    +
    + +
    +
    +upload_sources(sources=None, src_dir=None)[source]¶
    +
    + +
    +
    +upload_start_command(overwrite=False)[source]¶
    +
    + +
    +
    +upload_stdin(stdin=None)[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.channel module¶

    +
    +
    +class nepi.resources.linux.channel.LinuxChannel(ec, guid)[source]¶
    +

    Bases: nepi.execution.resource.ResourceManager

    +
    +
    +log_message(msg)[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.debfuncs module¶

    +
    +
    +nepi.resources.linux.debfuncs.install_packages_command(os, packages)[source]¶
    +
    + +
    +
    +nepi.resources.linux.debfuncs.remove_packages_command(os, packages)[source]¶
    +
    + +
    +
    +

    nepi.resources.linux.gretunnel module¶

    +
    +
    +class nepi.resources.linux.gretunnel.LinuxGRETunnel(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.tunnel.LinuxTunnel

    +
    +
    +check_state_connection()[source]¶
    +
    + +
    +
    +establish_connection(endpoint, remote_endpoint, data)[source]¶
    +
    + +
    +
    +get_endpoints()[source]¶
    +

    Returns the list of RM that are endpoints to the tunnel

    +
    + +
    +
    +initiate_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    +
    +log_message(msg)[source]¶
    +
    + +
    +
    +terminate_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    +
    +verify_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.interface module¶

    +
    +
    +class nepi.resources.linux.interface.LinuxInterface(ec, guid)[source]¶
    +

    Bases: nepi.execution.resource.ResourceManager

    +
    +
    +add_set_hooks()[source]¶
    +
    + +
    +
    +channel[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_discover()[source]¶
    +
    + +
    +
    +do_provision()[source]¶
    +
    + +
    +
    +do_release()[source]¶
    +
    + +
    +
    +load_configuration(devname, mac, ip4, mask4, ip6, mask6, mtu, up)[source]¶
    +
    + +
    +
    +log_message(msg)[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +set_hook_mtu(oldval, newval)[source]¶
    +
    + +
    +
    +set_hook_up(oldval, newval)[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.mtr module¶

    +
    +
    +class nepi.resources.linux.mtr.LinuxMtr(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.node module¶

    +
    +
    +class nepi.resources.linux.node.ExitCode[source]¶
    +

    Error codes that the rexitcode function can return if unable to +check the exit code of a spawned process

    +
    +
    +CORRUPTFILE = -2¶
    +
    + +
    +
    +ERROR = -3¶
    +
    + +
    +
    +FILENOTFOUND = -1¶
    +
    + +
    +
    +OK = 0¶
    +
    + +
    + +
    +
    +class nepi.resources.linux.node.LinuxNode(ec, guid)[source]¶
    +

    Bases: nepi.execution.resource.ResourceManager

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • ec (ExperimentController) – The Experiment controller
    • +
    • guid (int) – guid of the RM
    • +
    +
    +
    + +
    +

    Note

    +

    There are different ways in which commands can be executed using the +LinuxNode interface (i.e. ‘execute’ - blocking and non blocking, ‘run’, +‘run_and_wait’).

    +

    Brief explanation:

    +
    +
      +
    • ‘execute’ (blocking mode) :

      +
      +

      HOW IT WORKS: ‘execute’, forks a process and run the +command, synchronously, attached to the terminal, in +foreground. +The execute method will block until the command returns +the result on ‘out’, ‘err’ (so until it finishes executing).

      +

      USAGE: short-lived commands that must be executed attached +to a terminal and in foreground, for which it IS necessary +to block until the command has finished (e.g. if you want +to run ‘ls’ or ‘cat’).

      +
      +
    • +
    • ‘execute’ (NON blocking mode - blocking = False) :

      +
      +

      HOW IT WORKS: Same as before, except that execute method +will return immediately (even if command still running).

      +

      USAGE: long-lived commands that must be executed attached +to a terminal and in foreground, but for which it is not +necessary to block until the command has finished. (e.g. +start an application using X11 forwarding)

      +
      +
    • +
    +
    +
      +
    • ‘run’ :

      +
      +

      HOW IT WORKS: Connects to the host ( using SSH if remote) +and launches the command in background, detached from any +terminal (daemonized), and returns. The command continues to +run remotely, but since it is detached from the terminal, +its pipes (stdin, stdout, stderr) can’t be redirected to the +console (as normal non detached processes would), and so they +are explicitly redirected to files. The pidfile is created as +part of the process of launching the command. The pidfile +holds the pid and ppid of the process forked in background, +so later on it is possible to check whether the command is still +running.

      +
      +

      USAGE: long-lived commands that can run detached in background, +for which it is NOT necessary to block (wait) until the command +has finished. (e.g. start an application that is not using X11 +forwarding. It can run detached and remotely in background)

      +
      +
      +
    • +
    • ‘run_and_wait’ :

      +
      +

      HOW IT WORKS: Similar to ‘run’ except that it ‘blocks’ until +the command has finished execution. It also checks whether +errors occurred during runtime by reading the exitcode file, +which contains the exit code of the command that was run +(checking stderr only is not always reliable since many +commands throw debugging info to stderr and the only way to +automatically know whether an error really happened is to +check the process exit code).

      +

      Another difference with respect to ‘run’, is that instead +of directly executing the command as a bash command line, +it uploads the command to a bash script and runs the script. +This allows to use the bash script to debug errors, since +it remains at the remote host and can be run manually to +reproduce the error.

      +

      USAGE: medium-lived commands that can run detached in +background, for which it IS necessary to block (wait) until +the command has finished. (e.g. Package installation, +source compilation, file download, etc)

      +
      +
    • +
    +
    +
    +
    +
    +
    +bin_dir[source]¶
    +
    + +
    +
    +check_errors(home, ecodefile='exitcode', stderr='stderr')[source]¶
    +

    Checks whether errors occurred while running a command. +It first checks the exit code for the command, and only if the +exit code is an error one it returns the error output.

    +
    + +
    +
    +check_output(home, filename)[source]¶
    +

    Retrives content of file

    +
    + +
    +
    +clean_experiment()[source]¶
    +

    Cleans all experiment related files in the Linux host. +It preserves NEPI files and folders that have a multi experiment +scope.

    +
    + +
    +
    +clean_home()[source]¶
    +

    Cleans all NEPI related folders in the Linux host

    +
    + +
    +
    +clean_processes()[source]¶
    +
    + +
    +
    +copy(src, dst)[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_provision()[source]¶
    +
    + +
    +
    +do_release()[source]¶
    +
    + +
    +
    +download(src, dst, raise_on_error=True)[source]¶
    +
    + +
    +
    +execute(command, sudo=False, env=None, tty=False, forward_x11=False, retry=3, connect_timeout=30, strict_host_checking=False, persistent=True, blocking=True, with_lock=False)[source]¶
    +

    Notice that this invocation will block until the +execution finishes. If this is not the desired behavior, +use ‘run’ instead.

    +
    + +
    +
    +exitcode(home, ecodefile='exitcode')[source]¶
    +

    Get the exit code of an application. +Returns an integer value with the exit code

    +
    + +
    +
    +exp_dir[source]¶
    +
    + +
    +
    +exp_home[source]¶
    +
    + +
    +
    +filter_existing_files(src, dst)[source]¶
    +

    Removes files that already exist in the Linux host from src list

    +
    + +
    +
    +find_home()[source]¶
    +

    Retrieves host home directory

    +
    + +
    +
    +format_environment(env, inline=False)[source]¶
    +
    +
    Formats the environment variables for a command to be executed
    +
    +
    either as an inline command +(i.e. export PYTHONPATH=src/..; export LALAL= ..;python script.py) or +as a bash script (i.e. export PYTHONPATH=src/..
    +

    export LALA=..

    +
    +
    +

    )

    +
    + +
    +
    +get_os()[source]¶
    +
    + +
    +
    +getpid(home, pidfile='pidfile')[source]¶
    +
    + +
    +
    +home_dir[source]¶
    +
    + +
    +
    +install_packages(packages, home, run_home=None, raise_on_error=True)[source]¶
    +

    Install packages in the Linux host.

    +

    ‘home’ is the directory to upload the package installation script. +‘run_home’ is the directory from where to execute the script.

    +
    + +
    +
    +install_packages_command(packages)[source]¶
    +
    + +
    +
    +is_alive()[source]¶
    +

    Checks if host is responsive

    +
    + +
    +
    +kill(pid, ppid, sudo=False)[source]¶
    +
    + +
    +
    +lib_dir[source]¶
    +
    + +
    +
    +localhost[source]¶
    +
    + +
    +
    +log_message(msg)[source]¶
    +
    + +
    +
    +mkdir(paths, clean=False)[source]¶
    +

    Paths is either a single remote directory path to create, +or a list of directories to create.

    +
    + +
    +
    +nepi_home[source]¶
    +
    + +
    +
    +node_home[source]¶
    +
    + +
    +
    +os[source]¶
    +
    + +
    +
    +remove_packages(packages, home, run_home=None, raise_on_error=True)[source]¶
    +

    Uninstall packages from the Linux host.

    +

    ‘home’ is the directory to upload the package un-installation script. +‘run_home’ is the directory from where to execute the script.

    +
    + +
    +
    +rmdir(paths)[source]¶
    +

    Paths is either a single remote directory path to delete, +or a list of directories to delete.

    +
    + +
    +
    +run(command, home, create_home=False, pidfile='pidfile', stdin=None, stdout='stdout', stderr='stderr', sudo=False, tty=False, strict_host_checking=False)[source]¶
    +
    + +
    +
    +run_and_wait(command, home, shfile='cmd.sh', env=None, overwrite=True, wait_run=True, pidfile='pidfile', ecodefile='exitcode', stdin=None, stdout='stdout', stderr='stderr', sudo=False, tty=False, raise_on_error=True)[source]¶
    +

    Uploads the ‘command’ to a bash script in the host. +Then runs the script detached in background in the host, and +busy-waites until the script finishes executing.

    +
    + +
    +
    +run_home[source]¶
    +
    + +
    +
    +share_dir[source]¶
    +
    + +
    +
    +src_dir[source]¶
    +
    + +
    +
    +status(pid, ppid)[source]¶
    +
    + +
    +
    +upload(src, dst, text=False, overwrite=True, raise_on_error=True)[source]¶
    +

    Copy content to destination

    +
    +
    src string with the content to copy. Can be:
    +
      +
    • plain text
    • +
    • a string with the path to a local file
    • +
    • a string with a semi-colon separeted list of local files
    • +
    • a string with a local directory
    • +
    +
    +
    dst string with destination path on the remote host (remote is
    +
    always self.host)
    +
    +

    text src is text input, it must be stored into a temp file before +uploading

    +
    + +
    +
    +upload_command(command, shfile='cmd.sh', ecodefile='exitcode', overwrite=True, env=None)[source]¶
    +

    Saves the command as a bash script file in the remote host, and +forces to save the exit code of the command execution to the ecodefile

    +
    + +
    +
    +use_deb[source]¶
    +
    + +
    +
    +use_rpm[source]¶
    +
    + +
    +
    +usr_dir[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    +
    +wait_pid(home, pidfile='pidfile', raise_on_error=False)[source]¶
    +

    Waits until the pid file for the command is generated, +and returns the pid and ppid of the process

    +
    + +
    +
    +wait_run(pid, ppid, trial=0)[source]¶
    +

    wait for a remote process to finish execution

    +
    + +
    + +
    +
    +class nepi.resources.linux.node.OSType[source]¶
    +

    Supported flavors of Linux OS

    +
    +
    +DEBIAN = 1¶
    +
    + +
    +
    +FEDORA = 4¶
    +
    + +
    +
    +FEDORA_12 = 20¶
    +
    + +
    +
    +FEDORA_14 = 36¶
    +
    + +
    +
    +FEDORA_8 = 12¶
    +
    + +
    +
    +UBUNTU = 2¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.nping module¶

    +
    +
    +class nepi.resources.linux.nping.LinuxNPing(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.ping module¶

    +
    +
    +class nepi.resources.linux.ping.LinuxPing(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.route module¶

    +
    +
    +class nepi.resources.linux.route.LinuxRoute(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +device[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +do_stop()[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +upload_sources()[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.rpmfuncs module¶

    +
    +
    +nepi.resources.linux.rpmfuncs.install_packages_command(os, packages)[source]¶
    +
    + +
    +
    +nepi.resources.linux.rpmfuncs.install_rpmfusion_command(os)[source]¶
    +
    + +
    +
    +nepi.resources.linux.rpmfuncs.remove_packages_command(os, packages)[source]¶
    +
    + +
    +
    +

    nepi.resources.linux.tap module¶

    +
    +
    +class nepi.resources.linux.tap.LinuxTap(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +IFF_TAP = 2¶
    +
    + +
    +
    +IFF_TUN = 1¶
    +
    + +
    +
    +check_status()[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_release()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +do_stop()[source]¶
    +
    + +
    +
    +establish_udp_connection(remote_endpoint, connection_app_home, connection_run_home, port)[source]¶
    +
    + +
    +
    +gre_connect(remote_endpoint, connection_app_home, connection_run_home)[source]¶
    +
    + +
    +
    +gre_enabled[source]¶
    +
    + +
    +
    +initiate_udp_connection(remote_endpoint, connection_app_home, connection_run_home, cipher, cipher_key, bwlimit, txqueuelen)[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +sock_name[source]¶
    +
    + +
    +
    +state[source]¶
    +
    + +
    +
    +terminate_connection(remote_endpoint, connection_app_home, connection_run_home)[source]¶
    +
    + +
    +
    +udp_connect(remote_endpoint, connection_app_home, connection_run_home, cipher, cipher_key, bwlimit, txqueuelen)[source]¶
    +
    + +
    +
    +upload_sources()[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    +
    +verify_connection(remote_endpoint, connection_app_home, connection_run_home)[source]¶
    +
    + +
    +
    +vif_prefix[source]¶
    +
    + +
    +
    +vif_type[source]¶
    +
    + +
    +
    +vif_type_flag[source]¶
    +
    + +
    +
    +wait_file(home, filename)[source]¶
    +

    Waits until file on endpoint is generated

    +
    + +
    + +
    +
    +

    nepi.resources.linux.tcpdump module¶

    +
    +
    +class nepi.resources.linux.tcpdump.LinuxTcpdump(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.traceroute module¶

    +
    +
    +class nepi.resources.linux.traceroute.LinuxTraceroute(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.tun module¶

    +
    +
    +class nepi.resources.linux.tun.LinuxTun(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.tap.LinuxTap

    +
    + +
    +
    +

    nepi.resources.linux.tunnel module¶

    +
    +
    +class nepi.resources.linux.tunnel.LinuxTunnel(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +app_home(endpoint)[source]¶
    +
    + +
    +
    +check_state_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_provision()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +do_stop()[source]¶
    +

    Stops application execution

    +
    + +
    +
    +endpoint1[source]¶
    +
    + +
    +
    +endpoint2[source]¶
    +
    + +
    +
    +endpoint_mkdir(endpoint)[source]¶
    +
    + +
    +
    +establish_connection(endpoint, remote_endpoint, data)[source]¶
    +
    + +
    +
    +get_endpoints()[source]¶
    +

    Returns the list of RM that are endpoints to the tunnel

    +
    + +
    +
    +initiate_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    +
    +log_message(msg)[source]¶
    +
    + +
    +
    +run_home(endpoint)[source]¶
    +
    + +
    +
    +state[source]¶
    +

    Returns the state of the application

    +
    + +
    +
    +terminate_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    +
    +verify_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.udptest module¶

    +
    +
    +class nepi.resources.linux.udptest.LinuxUdpTest(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +

    Uses the hpcbench udptest tool to gather UDP measurements. +Measurements require two ends, a server and a client RM.

    +

    http://hpcbench.sourceforge.net/

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.udptunnel module¶

    +
    +
    +class nepi.resources.linux.udptunnel.LinuxUdpTunnel(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.tunnel.LinuxTunnel

    +
    +
    +check_state_connection()[source]¶
    +
    + +
    +
    +establish_connection(endpoint, remote_endpoint, port)[source]¶
    +
    + +
    +
    +get_endpoints()[source]¶
    +

    Returns the list of RM that are endpoints to the tunnel

    +
    + +
    +
    +initiate_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    +
    +log_message(msg)[source]¶
    +
    + +
    +
    +terminate_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    +
    +verify_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.linux.netns.html b/doc/sphinx/_build/html/_layout/nepi.resources.linux.netns.html new file mode 100644 index 00000000..1a34b535 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.linux.netns.html @@ -0,0 +1,285 @@ + + + + + + + + nepi.resources.linux.netns package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + +
    +
    +
    +
    + +
    +

    nepi.resources.linux.netns package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.linux.netns.netnsclient module¶

    +
    +
    +class nepi.resources.linux.netns.netnsclient.LinuxNetNSClient(emulation)[source]¶
    +

    Bases: nepi.resources.netns.netnsclient.NetNSClient

    +
    +
    +create(*args, **kwargs)[source]¶
    +
    + +
    +
    +emulation[source]¶
    +
    + +
    +
    +flush(*args, **kwargs)[source]¶
    +
    + +
    +
    +get(*args, **kwargs)[source]¶
    +
    + +
    +
    +invoke(*args, **kwargs)[source]¶
    +
    + +
    +
    +send_msg(msg_type, *args, **kwargs)[source]¶
    +
    + +
    +
    +set(*args, **kwargs)[source]¶
    +
    + +
    +
    +shutdown(*args, **kwargs)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.netns.netnsemulation module¶

    +
    +
    +class nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication, nepi.resources.netns.netnsemulation.NetNSEmulation

    +
    +
    +clone_command(name, repo, src)[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_release()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +

    Starts execution execution

    +
    + +
    +
    +do_stop()[source]¶
    +

    Stops simulation execution

    +
    + +
    +
    +netns_repo[source]¶
    +
    + +
    +
    +netns_src[source]¶
    +
    + +
    +
    +netns_version[source]¶
    +
    + +
    +
    +python_passfd_repo[source]¶
    +
    + +
    +
    +python_passfd_src[source]¶
    +
    + +
    +
    +python_passfd_version[source]¶
    +
    + +
    +
    +python_unshare_repo[source]¶
    +
    + +
    +
    +python_unshare_src[source]¶
    +
    + +
    +
    +python_unshare_version[source]¶
    +
    + +
    +
    +remote_socket[source]¶
    +
    + +
    +
    +replace_paths(command)[source]¶
    +

    Replace all special path tags with shell-escaped actual paths.

    +
    + +
    +
    +socket_name[source]¶
    +
    + +
    +
    +upload_extra_sources(sources=None, src_dir=None)[source]¶
    +
    + +
    +
    +upload_sources()[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    +
    +wait_remote_socket()[source]¶
    +

    Waits until the remote socket is created

    +
    + +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.ccn.html b/doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.ccn.html new file mode 100644 index 00000000..5098df24 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.ccn.html @@ -0,0 +1,186 @@ + + + + + + + + nepi.resources.linux.ns3.ccn package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +

    nepi.resources.linux.ns3.ccn package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication module¶

    +
    +
    +class nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication.LinuxNS3DceCCNCat(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication

    +
    + +
    +
    +

    nepi.resources.linux.ns3.ccn.ns3ccndceapplication module¶

    +
    +
    +class nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3ccndceapplication.NS3BaseCCNDceApplication

    +
    + +
    +
    +

    nepi.resources.linux.ns3.ccn.ns3ccnddceapplication module¶

    +
    +
    +class nepi.resources.linux.ns3.ccn.ns3ccnddceapplication.LinuxNS3DceCCND(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication

    +
    +
    +version[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication module¶

    +
    +
    +class nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication.LinuxNS3DceCCNPeek(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication

    +
    + +
    +
    +

    nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication module¶

    +
    +
    +class nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication.LinuxNS3DceCCNPoke(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication

    +
    + +
    +
    +

    nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication module¶

    +
    +
    +class nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication.LinuxNS3DceCCNR(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication

    +
    + +
    +
    +

    nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication module¶

    +
    +
    +class nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication.LinuxNS3DceFIBEntry(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication

    +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.html b/doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.html new file mode 100644 index 00000000..9f1cc83c --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.html @@ -0,0 +1,536 @@ + + + + + + + + nepi.resources.linux.ns3 package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +

    nepi.resources.linux.ns3 package¶

    + +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.linux.ns3.fdudptunnel module¶

    +
    +
    +class nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.udptunnel.LinuxUdpTunnel

    +
    +
    +app_home(endpoint)[source]¶
    +
    + +
    +
    +check_state_connection()[source]¶
    +
    + +
    +
    +endpoint1[source]¶
    +
    + +
    +
    +endpoint2[source]¶
    +
    + +
    +
    +endpoint_mkdir(endpoint)[source]¶
    +
    + +
    +
    +endpoint_node(endpoint)[source]¶
    +
    + +
    +
    +establish(endpoint, remote_endpoint, port)[source]¶
    +
    + +
    +
    +establish_connection(endpoint, remote_endpoint, port)[source]¶
    +
    + +
    +
    +get_endpoints()[source]¶
    +

    Returns the list of RM that are endpoints to the tunnel

    +
    + +
    +
    +initiate(endpoint, remote_endpoint, address, cipher, cipher_key, bwlimit, txqueuelen)[source]¶
    +
    + +
    +
    +initiate_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    +
    +log_message(msg)[source]¶
    +
    + +
    +
    +node1[source]¶
    +
    + +
    +
    +node2[source]¶
    +
    + +
    +
    +pi[source]¶
    +
    + +
    +
    +run_home(endpoint)[source]¶
    +
    + +
    +
    +terminate_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    +
    +upload_sources(endpoint)[source]¶
    +
    + +
    +
    +verify(endpoint)[source]¶
    +
    + +
    +
    +verify_connection(endpoint, remote_endpoint)[source]¶
    +
    + +
    +
    +wait_file(endpoint, filename)[source]¶
    +

    Waits until file on endpoint is generated

    +
    + +
    +
    +wait_local_port(endpoint)[source]¶
    +

    Waits until the local_port file for the endpoint is generated, +and returns the port number

    +
    + +
    +
    +wait_result(endpoint)[source]¶
    +

    Waits until the return code file for the endpoint is generated

    +
    + +
    + +
    +
    +

    nepi.resources.linux.ns3.ns3client module¶

    +
    +
    +class nepi.resources.linux.ns3.ns3client.LinuxNS3Client(simulation)[source]¶
    +

    Bases: nepi.resources.ns3.ns3client.NS3Client

    +
    +
    +create(*args, **kwargs)[source]¶
    +
    + +
    +
    +factory(*args, **kwargs)[source]¶
    +
    + +
    +
    +flush(*args, **kwargs)[source]¶
    +
    + +
    +
    +get(*args, **kwargs)[source]¶
    +
    + +
    +
    +invoke(*args, **kwargs)[source]¶
    +
    + +
    +
    +send_msg(msg_type, *args, **kwargs)[source]¶
    +
    + +
    +
    +set(*args, **kwargs)[source]¶
    +
    + +
    +
    +shutdown(*args, **kwargs)[source]¶
    +
    + +
    +
    +simulation[source]¶
    +
    + +
    +
    +start(*args, **kwargs)[source]¶
    +
    + +
    +
    +stop(*args, **kwargs)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.linux.ns3.ns3dceapplication module¶

    +
    +
    +class nepi.resources.linux.ns3.ns3dceapplication.LinuxNS3DceApplication(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication

    +
    + +
    +
    +

    nepi.resources.linux.ns3.ns3pingdceapplication module¶

    +
    +
    +class nepi.resources.linux.ns3.ns3pingdceapplication.LinuxDcePing(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ns3.ns3dceapplication.LinuxNS3DceApplication

    +
    + +
    +
    +

    nepi.resources.linux.ns3.ns3simulation module¶

    +
    +
    +class nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication, nepi.resources.ns3.ns3simulation.NS3Simulation

    +
    +
    +configure()[source]¶
    +
    + +
    +
    +dce_helper[source]¶
    +
    + +
    +
    +dce_repo[source]¶
    +
    + +
    +
    +dce_src_location[source]¶
    +
    + +
    +
    +dce_version[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_release()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +

    Starts simulation execution

    +
    + +
    +
    +do_stop()[source]¶
    +

    Stops simulation execution

    +
    + +
    +
    +enable_dce[source]¶
    +
    + +
    +
    +ns3_build_location[source]¶
    +
    + +
    +
    +ns3_repo[source]¶
    +
    + +
    +
    +ns3_src_location[source]¶
    +
    + +
    +
    +pygccxml_version[source]¶
    +
    + +
    +
    +remote_socket[source]¶
    +
    + +
    +
    +replace_paths(command)[source]¶
    +

    Replace all special path tags with shell-escaped actual paths.

    +
    + +
    +
    +socket_name[source]¶
    +
    + +
    +
    +state[source]¶
    +
    + +
    +
    +trace(name, attr='all', block=512, offset=0)[source]¶
    +
    + +
    +
    +upload_extra_sources(sources=None, src_dir=None)[source]¶
    +
    + +
    +
    +upload_sources()[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    +
    +wait_remote_socket()[source]¶
    +

    Waits until the remote socket is created

    +
    + +
    + +
    + +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.netns.html b/doc/sphinx/_build/html/_layout/nepi.resources.netns.html new file mode 100644 index 00000000..6df18f48 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.netns.html @@ -0,0 +1,617 @@ + + + + + + + + nepi.resources.netns package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +

    nepi.resources.netns package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.netns.netnsapplication module¶

    +
    +
    +class nepi.resources.netns.netnsapplication.NetNSApplication(ec, guid)[source]¶
    +

    Bases: nepi.resources.netns.netnsbase.NetNSBase

    +
    +
    +do_start()[source]¶
    +
    + +
    +
    +emulation[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +state[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.netns.netnsbase module¶

    +
    +
    +class nepi.resources.netns.netnsbase.NetNSBase(ec, guid)[source]¶
    +

    Bases: nepi.execution.resource.ResourceManager

    +
    +
    +connected[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_provision()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +do_stop()[source]¶
    +
    + +
    +
    +get(name)[source]¶
    +
    + +
    +
    +set(name, value)[source]¶
    +
    + +
    +
    +state[source]¶
    +
    + +
    +
    +trace(name, attr='all', block=512, offset=0)[source]¶
    +
    + +
    +
    +uuid[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.netns.netnsclient module¶

    +
    +
    +class nepi.resources.netns.netnsclient.NetNSClient[source]¶
    +

    Bases: object

    +

    Common Interface for NS3 client classes

    +
    +
    +create(*args, **kwargs)[source]¶
    +
    + +
    +
    +flush(*args, **kwargs)[source]¶
    +
    + +
    +
    +get(*args, **kwargs)[source]¶
    +
    + +
    +
    +invoke(*args, **kwargs)[source]¶
    +
    + +
    +
    +set(*args, **kwargs)[source]¶
    +
    + +
    +
    +shutdown(*args, **kwargs)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.netns.netnsemulation module¶

    +
    +
    +class nepi.resources.netns.netnsemulation.NetNSEmulation[source]¶
    +

    Bases: object

    +
    +
    +client[source]¶
    +
    + +
    +
    +create(*args, **kwargs)[source]¶
    +
    + +
    +
    +emu_get(*args, **kwargs)[source]¶
    +
    + +
    +
    +emu_set(*args, **kwargs)[source]¶
    +
    + +
    +
    +flush(*args, **kwargs)[source]¶
    +
    + +
    +
    +invoke(*args, **kwargs)[source]¶
    +
    + +
    +
    +shutdown(*args, **kwargs)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.netns.netnsinterface module¶

    +
    +
    +class nepi.resources.netns.netnsinterface.NetNSInterface(ec, guid)[source]¶
    +

    Bases: nepi.resources.netns.netnsbase.NetNSBase

    +
    + +
    +
    +

    nepi.resources.netns.netnsipv4address module¶

    +
    +
    +class nepi.resources.netns.netnsipv4address.NetNSIPv4Address(ec, guid)[source]¶
    +

    Bases: nepi.resources.netns.netnsbase.NetNSBase

    +
    +
    +emulation[source]¶
    +
    + +
    +
    +interface[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.netns.netnsnode module¶

    +
    +
    +class nepi.resources.netns.netnsnode.NetNSNode(ec, guid)[source]¶
    +

    Bases: nepi.resources.netns.netnsbase.NetNSBase

    +
    +
    +emulation[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.netns.netnsnodeinterface module¶

    +
    +
    +class nepi.resources.netns.netnsnodeinterface.NetNSNodeInterface(ec, guid)[source]¶
    +

    Bases: nepi.resources.netns.netnsinterface.NetNSInterface

    +
    +
    +emulation[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +switch[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.netns.netnsroute module¶

    +
    +
    +class nepi.resources.netns.netnsroute.NetNSIPv4Route(ec, guid)[source]¶
    +

    Bases: nepi.resources.netns.netnsbase.NetNSBase

    +
    +
    +emulation[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.netns.netnsserver module¶

    +
    +
    +class nepi.resources.netns.netnsserver.NetNSWrapperMessage[source]¶
    +
    +
    +CREATE = 'CREATE'¶
    +
    + +
    +
    +FLUSH = 'FLUSH'¶
    +
    + +
    +
    +GET = 'GET'¶
    +
    + +
    +
    +INVOKE = 'INVOKE'¶
    +
    + +
    +
    +SET = 'SET'¶
    +
    + +
    +
    +SHUTDOWN = 'SHUTDOWN'¶
    +
    + +
    + +
    +
    +nepi.resources.netns.netnsserver.create_socket(socket_name)[source]¶
    +
    + +
    +
    +nepi.resources.netns.netnsserver.get_options()[source]¶
    +
    + +
    +
    +nepi.resources.netns.netnsserver.handle_message(wrapper, msg_type, args, kwargs)[source]¶
    +
    + +
    +
    +nepi.resources.netns.netnsserver.recv_msg(conn)[source]¶
    +
    + +
    +
    +nepi.resources.netns.netnsserver.run_server(socket_name, level=20, enable_dump=False)[source]¶
    +
    + +
    +
    +nepi.resources.netns.netnsserver.send_reply(conn, reply)[source]¶
    +
    + +
    +
    +

    nepi.resources.netns.netnsswitch module¶

    +
    +
    +class nepi.resources.netns.netnsswitch.NetNSSwitch(ec, guid)[source]¶
    +

    Bases: nepi.resources.netns.netnsbase.NetNSBase

    +
    +
    +emulation[source]¶
    +
    + +
    +
    +interface[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.netns.netnswrapper module¶

    +
    +
    +class nepi.resources.netns.netnswrapper.NetNSWrapper(loglevel=20, enable_dump=False)[source]¶
    +

    Bases: object

    +
    +
    +create(clazzname, *args)[source]¶
    +

    This method should be used to construct netns objects

    +
    + +
    +
    +debuger[source]¶
    +
    + +
    +
    +get(uuid, name)[source]¶
    +
    + +
    +
    +get_object(uuid)[source]¶
    +
    + +
    +
    +invoke(uuid, operation, *args, **kwargs)[source]¶
    +
    + +
    +
    +logger[source]¶
    +
    + +
    +
    +make_uuid()[source]¶
    +
    + +
    +
    +replace_args(args)[source]¶
    +
    + +
    +
    +replace_kwargs(kwargs)[source]¶
    +
    + +
    +
    +set(uuid, name, value)[source]¶
    +
    + +
    +
    +shutdown()[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.netns.netnswrapper_debug module¶

    +
    +
    +class nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger(enabled)[source]¶
    +

    Bases: object

    +
    +
    +dump_create(uuid, clazzname, args)[source]¶
    +
    + +
    +
    +dump_factory(uuid, type_name, kwargs)[source]¶
    +
    + +
    +
    +dump_get(uuid, name)[source]¶
    +
    + +
    +
    +dump_header()[source]¶
    +
    + +
    +
    +dump_invoke(newuuid, uuid, operation, args, kwargs)[source]¶
    +
    + +
    +
    +dump_set(uuid, name, value)[source]¶
    +
    + +
    +
    +dump_shutdown()[source]¶
    +
    + +
    +
    +dump_to_script(command)[source]¶
    +
    + +
    +
    +enabled[source]¶
    +
    + +
    +
    +format_args(args)[source]¶
    +
    + +
    +
    +format_kwargs(kwargs)[source]¶
    +
    + +
    +
    +format_value(value)[source]¶
    +
    + +
    +
    +script_path[source]¶
    +
    + +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.ns3.classes.html b/doc/sphinx/_build/html/_layout/nepi.resources.ns3.classes.html new file mode 100644 index 00000000..38f606a7 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.ns3.classes.html @@ -0,0 +1,1171 @@ + + + + + + + + nepi.resources.ns3.classes package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + +
    +
    +
    +
    + +
    +

    nepi.resources.ns3.classes package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.ns3.classes.aarf_wifi_manager module¶

    +
    +
    +class nepi.resources.ns3.classes.aarf_wifi_manager.NS3AarfWifiManager(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

    +
    + +
    +
    +

    nepi.resources.ns3.classes.aarfcd_wifi_manager module¶

    +
    +
    +class nepi.resources.ns3.classes.aarfcd_wifi_manager.NS3AarfcdWifiManager(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

    +
    + +
    +
    +

    nepi.resources.ns3.classes.adhoc_wifi_mac module¶

    +
    +
    +class nepi.resources.ns3.classes.adhoc_wifi_mac.NS3AdhocWifiMac(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac

    +
    + +
    +
    +

    nepi.resources.ns3.classes.aloha_noack_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.aloha_noack_net_device.NS3AlohaNoackNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.amrr_wifi_manager module¶

    +
    +
    +class nepi.resources.ns3.classes.amrr_wifi_manager.NS3AmrrWifiManager(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

    +
    + +
    +
    +

    nepi.resources.ns3.classes.ap_wifi_mac module¶

    +
    +
    +class nepi.resources.ns3.classes.ap_wifi_mac.NS3ApWifiMac(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac

    +
    + +
    +
    +

    nepi.resources.ns3.classes.arf_wifi_manager module¶

    +
    +
    +class nepi.resources.ns3.classes.arf_wifi_manager.NS3ArfWifiManager(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

    +
    + +
    +
    +

    nepi.resources.ns3.classes.arp_l3protocol module¶

    +
    +
    +class nepi.resources.ns3.classes.arp_l3protocol.NS3ArpL3Protocol(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3arpl3protocol.NS3BaseArpL3Protocol

    +
    + +
    +
    +

    nepi.resources.ns3.classes.base_station_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.base_station_net_device.NS3BaseStationNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.binary_error_model module¶

    +
    +
    +class nepi.resources.ns3.classes.binary_error_model.NS3BinaryErrorModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.binary_error_sixlow_model module¶

    +
    +
    +class nepi.resources.ns3.classes.binary_error_sixlow_model.NS3BinaryErrorSixlowModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.bridge_channel module¶

    +
    +
    +class nepi.resources.ns3.classes.bridge_channel.NS3BridgeChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.bridge_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.bridge_net_device.NS3BridgeNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.bulk_send_application module¶

    +
    +
    +class nepi.resources.ns3.classes.bulk_send_application.NS3BulkSendApplication(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

    +
    + +
    +
    +

    nepi.resources.ns3.classes.burst_error_model module¶

    +
    +
    +class nepi.resources.ns3.classes.burst_error_model.NS3BurstErrorModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.cara_wifi_manager module¶

    +
    +
    +class nepi.resources.ns3.classes.cara_wifi_manager.NS3CaraWifiManager(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

    +
    + +
    +
    +

    nepi.resources.ns3.classes.constant_acceleration_mobility_model module¶

    +
    +
    +class nepi.resources.ns3.classes.constant_acceleration_mobility_model.NS3ConstantAccelerationMobilityModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.constant_position_mobility_model module¶

    +
    +
    +class nepi.resources.ns3.classes.constant_position_mobility_model.NS3ConstantPositionMobilityModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.constant_rate_wifi_manager module¶

    +
    +
    +class nepi.resources.ns3.classes.constant_rate_wifi_manager.NS3ConstantRateWifiManager(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

    +
    + +
    +
    +

    nepi.resources.ns3.classes.constant_speed_propagation_delay_model module¶

    +
    +
    +class nepi.resources.ns3.classes.constant_speed_propagation_delay_model.NS3ConstantSpeedPropagationDelayModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationdelaymodel.NS3BasePropagationDelayModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.constant_velocity_mobility_model module¶

    +
    +
    +class nepi.resources.ns3.classes.constant_velocity_mobility_model.NS3ConstantVelocityMobilityModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.cost231propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.cost231propagation_loss_model.NS3Cost231PropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.csma_channel module¶

    +
    +
    +class nepi.resources.ns3.classes.csma_channel.NS3CsmaChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.csma_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.csma_net_device.NS3CsmaNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.drop_tail_queue module¶

    +
    +
    +class nepi.resources.ns3.classes.drop_tail_queue.NS3DropTailQueue(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3queue.NS3BaseQueue

    +
    + +
    +
    +

    nepi.resources.ns3.classes.dsrdsr_routing module¶

    +
    +
    +class nepi.resources.ns3.classes.dsrdsr_routing.NS3dsrDsrRouting(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    + +
    +
    +

    nepi.resources.ns3.classes.emu_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.emu_net_device.NS3EmuNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.error_channel module¶

    +
    +
    +class nepi.resources.ns3.classes.error_channel.NS3ErrorChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.error_channel_sixlow module¶

    +
    +
    +class nepi.resources.ns3.classes.error_channel_sixlow.NS3ErrorChannelSixlow(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.error_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.error_net_device.NS3ErrorNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.fd_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.fd_net_device.NS3FdNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3fdnetdevice.NS3BaseFdNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.fixed_rss_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.fixed_rss_loss_model.NS3FixedRssLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.friis_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.friis_propagation_loss_model.NS3FriisPropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.gauss_markov_mobility_model module¶

    +
    +
    +class nepi.resources.ns3.classes.gauss_markov_mobility_model.NS3GaussMarkovMobilityModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.hierarchical_mobility_model module¶

    +
    +
    +class nepi.resources.ns3.classes.hierarchical_mobility_model.NS3HierarchicalMobilityModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model.NS3HybridBuildingsPropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.icmpv4l4protocol module¶

    +
    +
    +class nepi.resources.ns3.classes.icmpv4l4protocol.NS3Icmpv4L4Protocol(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3icmpv4l4protocol.NS3BaseIcmpv4L4Protocol

    +
    + +
    +
    +

    nepi.resources.ns3.classes.icmpv6l4protocol module¶

    +
    +
    +class nepi.resources.ns3.classes.icmpv6l4protocol.NS3Icmpv6L4Protocol(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    + +
    +
    +

    nepi.resources.ns3.classes.ideal_wifi_manager module¶

    +
    +
    +class nepi.resources.ns3.classes.ideal_wifi_manager.NS3IdealWifiManager(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

    +
    + +
    +
    +

    nepi.resources.ns3.classes.ipv4l3protocol module¶

    +
    +
    +class nepi.resources.ns3.classes.ipv4l3protocol.NS3Ipv4L3Protocol(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3ipv4l3protocol.NS3BaseIpv4L3Protocol

    +
    + +
    +
    +

    nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model.NS3ItuR1411LosPropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model.NS3ItuR1411NlosOverRooftopPropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.jakes_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.jakes_propagation_loss_model.NS3JakesPropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model.NS3Kun2600MhzPropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.list_error_model module¶

    +
    +
    +class nepi.resources.ns3.classes.list_error_model.NS3ListErrorModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.log_distance_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.log_distance_propagation_loss_model.NS3LogDistancePropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.loopback_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.loopback_net_device.NS3LoopbackNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.lr_wpan_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.lr_wpan_net_device.NS3LrWpanNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.lte_enb_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.lte_enb_net_device.NS3LteEnbNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.lte_simple_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.lte_simple_net_device.NS3LteSimpleNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.lte_ue_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.lte_ue_net_device.NS3LteUeNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.matrix_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.matrix_propagation_loss_model.NS3MatrixPropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.mesh_point_device module¶

    +
    +
    +class nepi.resources.ns3.classes.mesh_point_device.NS3MeshPointDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.mesh_wifi_interface_mac module¶

    +
    +
    +class nepi.resources.ns3.classes.mesh_wifi_interface_mac.NS3MeshWifiInterfaceMac(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac

    +
    + +
    +
    +

    nepi.resources.ns3.classes.minstrel_wifi_manager module¶

    +
    +
    +class nepi.resources.ns3.classes.minstrel_wifi_manager.NS3MinstrelWifiManager(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

    +
    + +
    +
    +

    nepi.resources.ns3.classes.multi_model_spectrum_channel module¶

    +
    +
    +class nepi.resources.ns3.classes.multi_model_spectrum_channel.NS3MultiModelSpectrumChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.nakagami_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.nakagami_propagation_loss_model.NS3NakagamiPropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.nist_error_rate_model module¶

    +
    +
    +class nepi.resources.ns3.classes.nist_error_rate_model.NS3NistErrorRateModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3errorratemodel.NS3BaseErrorRateModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.node module¶

    +
    +
    +class nepi.resources.ns3.classes.node.NS3Node(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3node.NS3BaseNode

    +
    + +
    +
    +

    nepi.resources.ns3.classes.non_communicating_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.non_communicating_net_device.NS3NonCommunicatingNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.ocb_wifi_mac module¶

    +
    +
    +class nepi.resources.ns3.classes.ocb_wifi_mac.NS3OcbWifiMac(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac

    +
    + +
    +
    +

    nepi.resources.ns3.classes.oh_buildings_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.oh_buildings_propagation_loss_model.NS3OhBuildingsPropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.okumura_hata_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.okumura_hata_propagation_loss_model.NS3OkumuraHataPropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.on_off_application module¶

    +
    +
    +class nepi.resources.ns3.classes.on_off_application.NS3OnOffApplication(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

    +
    + +
    +
    +

    nepi.resources.ns3.classes.onoe_wifi_manager module¶

    +
    +
    +class nepi.resources.ns3.classes.onoe_wifi_manager.NS3OnoeWifiManager(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

    +
    + +
    +
    +

    nepi.resources.ns3.classes.packet_sink module¶

    +
    +
    +class nepi.resources.ns3.classes.packet_sink.NS3PacketSink(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

    +
    + +
    +
    +

    nepi.resources.ns3.classes.ping6 module¶

    +
    +
    +class nepi.resources.ns3.classes.ping6.NS3Ping6(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

    +
    + +
    +
    +

    nepi.resources.ns3.classes.point_to_point_channel module¶

    +
    +
    +class nepi.resources.ns3.classes.point_to_point_channel.NS3PointToPointChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.point_to_point_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.point_to_point_net_device.NS3PointToPointNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.point_to_point_remote_channel module¶

    +
    +
    +class nepi.resources.ns3.classes.point_to_point_remote_channel.NS3PointToPointRemoteChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.radvd module¶

    +
    +
    +class nepi.resources.ns3.classes.radvd.NS3Radvd(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

    +
    + +
    +
    +

    nepi.resources.ns3.classes.random_direction2d_mobility_model module¶

    +
    +
    +class nepi.resources.ns3.classes.random_direction2d_mobility_model.NS3RandomDirection2dMobilityModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.random_propagation_delay_model module¶

    +
    +
    +class nepi.resources.ns3.classes.random_propagation_delay_model.NS3RandomPropagationDelayModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationdelaymodel.NS3BasePropagationDelayModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.random_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.random_propagation_loss_model.NS3RandomPropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.random_walk2d_mobility_model module¶

    +
    +
    +class nepi.resources.ns3.classes.random_walk2d_mobility_model.NS3RandomWalk2dMobilityModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.random_waypoint_mobility_model module¶

    +
    +
    +class nepi.resources.ns3.classes.random_waypoint_mobility_model.NS3RandomWaypointMobilityModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.range_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.range_propagation_loss_model.NS3RangePropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.rate_error_model module¶

    +
    +
    +class nepi.resources.ns3.classes.rate_error_model.NS3RateErrorModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.receive_list_error_model module¶

    +
    +
    +class nepi.resources.ns3.classes.receive_list_error_model.NS3ReceiveListErrorModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.red_queue module¶

    +
    +
    +class nepi.resources.ns3.classes.red_queue.NS3RedQueue(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3queue.NS3BaseQueue

    +
    + +
    +
    +

    nepi.resources.ns3.classes.rraa_wifi_manager module¶

    +
    +
    +class nepi.resources.ns3.classes.rraa_wifi_manager.NS3RraaWifiManager(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

    +
    + +
    +
    +

    nepi.resources.ns3.classes.simple_channel module¶

    +
    +
    +class nepi.resources.ns3.classes.simple_channel.NS3SimpleChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.simple_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.simple_net_device.NS3SimpleNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.single_model_spectrum_channel module¶

    +
    +
    +class nepi.resources.ns3.classes.single_model_spectrum_channel.NS3SingleModelSpectrumChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.six_low_pan_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.six_low_pan_net_device.NS3SixLowPanNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.sta_wifi_mac module¶

    +
    +
    +class nepi.resources.ns3.classes.sta_wifi_mac.NS3StaWifiMac(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac

    +
    + +
    +
    +

    nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model module¶

    +
    +
    +class nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model.NS3SteadyStateRandomWaypointMobilityModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.subscriber_station_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.subscriber_station_net_device.NS3SubscriberStationNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.tap_bridge module¶

    +
    +
    +class nepi.resources.ns3.classes.tap_bridge.NS3TapBridge(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.tcp_l4protocol module¶

    +
    +
    +class nepi.resources.ns3.classes.tcp_l4protocol.NS3TcpL4Protocol(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    + +
    +
    +

    nepi.resources.ns3.classes.three_log_distance_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.three_log_distance_propagation_loss_model.NS3ThreeLogDistancePropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model module¶

    +
    +
    +class nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model.NS3TwoRayGroundPropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.uan_channel module¶

    +
    +
    +class nepi.resources.ns3.classes.uan_channel.NS3UanChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.udp_client module¶

    +
    +
    +class nepi.resources.ns3.classes.udp_client.NS3UdpClient(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

    +
    + +
    +
    +

    nepi.resources.ns3.classes.udp_echo_client module¶

    +
    +
    +class nepi.resources.ns3.classes.udp_echo_client.NS3UdpEchoClient(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

    +
    + +
    +
    +

    nepi.resources.ns3.classes.udp_echo_server module¶

    +
    +
    +class nepi.resources.ns3.classes.udp_echo_server.NS3UdpEchoServer(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

    +
    + +
    +
    +

    nepi.resources.ns3.classes.udp_l4protocol module¶

    +
    +
    +class nepi.resources.ns3.classes.udp_l4protocol.NS3UdpL4Protocol(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    + +
    +
    +

    nepi.resources.ns3.classes.udp_server module¶

    +
    +
    +class nepi.resources.ns3.classes.udp_server.NS3UdpServer(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

    +
    + +
    +
    +

    nepi.resources.ns3.classes.udp_trace_client module¶

    +
    +
    +class nepi.resources.ns3.classes.udp_trace_client.NS3UdpTraceClient(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

    +
    + +
    +
    +

    nepi.resources.ns3.classes.v4ping module¶

    +
    +
    +class nepi.resources.ns3.classes.v4ping.NS3V4Ping(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

    +
    + +
    +
    +

    nepi.resources.ns3.classes.virtual_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.virtual_net_device.NS3VirtualNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.waypoint_mobility_model module¶

    +
    +
    +class nepi.resources.ns3.classes.waypoint_mobility_model.NS3WaypointMobilityModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.wifi_net_device module¶

    +
    +
    +class nepi.resources.ns3.classes.wifi_net_device.NS3WifiNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifinetdevice.NS3BaseWifiNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.classes.yans_error_rate_model module¶

    +
    +
    +class nepi.resources.ns3.classes.yans_error_rate_model.NS3YansErrorRateModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3errorratemodel.NS3BaseErrorRateModel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.yans_wifi_channel module¶

    +
    +
    +class nepi.resources.ns3.classes.yans_wifi_channel.NS3YansWifiChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifichannel.NS3BaseWifiChannel

    +
    + +
    +
    +

    nepi.resources.ns3.classes.yans_wifi_phy module¶

    +
    +
    +class nepi.resources.ns3.classes.yans_wifi_phy.NS3YansWifiPhy(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3wifiphy.NS3BaseWifiPhy

    +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.ns3.html b/doc/sphinx/_build/html/_layout/nepi.resources.ns3.html new file mode 100644 index 00000000..5add2fcc --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.ns3.html @@ -0,0 +1,1239 @@ + + + + + + + + nepi.resources.ns3 package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + +
    +
    +
    +
    + +
    +

    nepi.resources.ns3 package¶

    +
    +

    Subpackages¶

    +
    + +
    +
    +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.ns3.ns3application module¶

    +
    +
    +class nepi.resources.ns3.ns3application.NS3BaseApplication(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +do_start()[source]¶
    +
    + +
    +
    +do_stop()[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +state[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3arpl3protocol module¶

    +
    +
    +class nepi.resources.ns3.ns3arpl3protocol.NS3BaseArpL3Protocol(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +node[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3base module¶

    +
    +
    +class nepi.resources.ns3.ns3base.NS3Base(ec, guid)[source]¶
    +

    Bases: nepi.execution.resource.ResourceManager

    +
    +
    +connected[source]¶
    +
    + +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_provision()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +do_stop()[source]¶
    +
    + +
    +
    +get(name)[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +set(name, value)[source]¶
    +
    + +
    +
    +simulation[source]¶
    +
    + +
    +
    +state[source]¶
    +
    + +
    +
    +trace(name, attr='all', block=512, offset=0)[source]¶
    +
    + +
    +
    +uuid[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3ccndceapplication module¶

    +
    +
    +class nepi.resources.ns3.ns3ccndceapplication.NS3BaseCCNDceApplication(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication

    +
    +
    +ccn_client_helper_uuid[source]¶
    +
    + +
    +
    +ccn_client_lock = <thread.lock object at 0x7f0290310f90>¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3channel module¶

    +
    +
    +class nepi.resources.ns3.ns3channel.NS3BaseChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +devices[source]¶
    +
    + +
    +
    +simulation[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3client module¶

    +
    +
    +class nepi.resources.ns3.ns3client.NS3Client[source]¶
    +

    Bases: object

    +

    Common Interface for NS3 client classes

    +
    +
    +create(*args, **kwargs)[source]¶
    +
    + +
    +
    +factory(*args, **kwargs)[source]¶
    +
    + +
    +
    +flush(*args, **kwargs)[source]¶
    +
    + +
    +
    +get(*args, **kwargs)[source]¶
    +
    + +
    +
    +invoke(*args, **kwargs)[source]¶
    +
    + +
    +
    +set(*args, **kwargs)[source]¶
    +
    + +
    +
    +shutdown(*args, **kwargs)[source]¶
    +
    + +
    +
    +start(*args, **kwargs)[source]¶
    +
    + +
    +
    +stop(*args, **kwargs)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3dceapplication module¶

    +
    +
    +class nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

    +
    +
    +do_start()[source]¶
    +
    + +
    +
    +do_stop()[source]¶
    +
    + +
    +
    +pid[source]¶
    +
    + +
    +
    +trace(name, attr='all', block=512, offset=0)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3dcehelper module¶

    +
    +
    +class nepi.resources.ns3.ns3dcehelper.NS3DceHelper(simulation)[source]¶
    +

    Bases: object

    +
    +
    +dce_application_lock[source]¶
    +
    + +
    +
    +dce_application_uuid[source]¶
    +
    + +
    +
    +dce_manager_lock[source]¶
    +
    + +
    +
    +dce_manager_uuid[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3errormodel module¶

    +
    +
    +class nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +device[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3errorratemodel module¶

    +
    +
    +class nepi.resources.ns3.ns3errorratemodel.NS3BaseErrorRateModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +node[source]¶
    +
    + +
    +
    +phy[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3fdnetdevice module¶

    +
    +
    +class nepi.resources.ns3.ns3fdnetdevice.NS3BaseFdNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    +
    +recv_fd()[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3icmpv4l4protocol module¶

    +
    +
    +class nepi.resources.ns3.ns3icmpv4l4protocol.NS3BaseIcmpv4L4Protocol(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +node[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3ipv4l3protocol module¶

    +
    +
    +class nepi.resources.ns3.ns3ipv4l3protocol.NS3BaseIpv4L3Protocol(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +node[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3mobilitymodel module¶

    +
    +
    +class nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    + +
    +
    +

    nepi.resources.ns3.ns3netdevice module¶

    +
    +
    +class nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +ascii_helper_uuid[source]¶
    +
    + +
    +
    +channel[source]¶
    +
    + +
    +
    +device_helper_uuid[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +queue[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3node module¶

    +
    +
    +class nepi.resources.ns3.ns3node.NS3BaseNode(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +arp[source]¶
    +
    + +
    +
    +dceapplications[source]¶
    +
    + +
    +
    +devices[source]¶
    +
    + +
    +
    +ipv4[source]¶
    +
    + +
    +
    +mobility[source]¶
    +
    + +
    +
    +node_id[source]¶
    +
    + +
    +
    +simulation[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3pipechanel module¶

    +
    +
    +class nepi.resources.ns3.ns3pipechanel.NS3BasePipeChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +

    Interconnects two FdNetDevices with a PIPE

    +
    +
    +devices[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3propagationdelaymodel module¶

    +
    +
    +class nepi.resources.ns3.ns3propagationdelaymodel.NS3BasePropagationDelayModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +channel[source]¶
    +
    + +
    +
    +simulation[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3propagationlossmodel module¶

    +
    +
    +class nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +channel[source]¶
    +
    + +
    +
    +simulation[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3queue module¶

    +
    +
    +class nepi.resources.ns3.ns3queue.NS3BaseQueue(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +device[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3route module¶

    +
    +
    +class nepi.resources.ns3.ns3route.NS3Route(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +node[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3server module¶

    +
    +
    +class nepi.resources.ns3.ns3server.NS3WrapperMessage[source]¶
    +
    +
    +CREATE = 'CREATE'¶
    +
    + +
    +
    +FACTORY = 'FACTORY'¶
    +
    + +
    +
    +FLUSH = 'FLUSH'¶
    +
    + +
    +
    +GET = 'GET'¶
    +
    + +
    +
    +INVOKE = 'INVOKE'¶
    +
    + +
    +
    +SET = 'SET'¶
    +
    + +
    +
    +SHUTDOWN = 'SHUTDOWN'¶
    +
    + +
    +
    +START = 'START'¶
    +
    + +
    +
    +STOP = 'STOP'¶
    +
    + +
    + +
    +
    +nepi.resources.ns3.ns3server.close_socket(sock)[source]¶
    +
    + +
    +
    +nepi.resources.ns3.ns3server.get_options()[source]¶
    +
    + +
    +
    +nepi.resources.ns3.ns3server.handle_message(ns3_wrapper, msg_type, args, kwargs)[source]¶
    +
    + +
    +
    +nepi.resources.ns3.ns3server.open_socket(socket_name)[source]¶
    +
    + +
    +
    +nepi.resources.ns3.ns3server.recv_msg(conn)[source]¶
    +
    + +
    +
    +nepi.resources.ns3.ns3server.run_server(socket_name, level=20, ns_log=None, enable_dump=False)[source]¶
    +
    + +
    +
    +nepi.resources.ns3.ns3server.send_reply(conn, reply)[source]¶
    +
    + +
    +
    +

    nepi.resources.ns3.ns3simulation module¶

    +
    +
    +class nepi.resources.ns3.ns3simulation.NS3Simulation[source]¶
    +

    Bases: object

    +
    +
    +client[source]¶
    +
    + +
    +
    +create(*args, **kwargs)[source]¶
    +
    + +
    +
    +factory(*args, **kwargs)[source]¶
    +
    + +
    +
    +flush(*args, **kwargs)[source]¶
    +
    + +
    +
    +invoke(*args, **kwargs)[source]¶
    +
    + +
    +
    +ns3_get(*args, **kwargs)[source]¶
    +
    + +
    +
    +ns3_set(*args, **kwargs)[source]¶
    +
    + +
    +
    +shutdown(*args, **kwargs)[source]¶
    +
    + +
    +
    +start(*args, **kwargs)[source]¶
    +
    + +
    +
    +stop(*args, **kwargs)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3wifichannel module¶

    +
    +
    +class nepi.resources.ns3.ns3wifichannel.NS3BaseWifiChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +phys[source]¶
    +
    + +
    +
    +simulation[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3wifimac module¶

    +
    +
    +class nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +device[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3wifinetdevice module¶

    +
    +
    +class nepi.resources.ns3.ns3wifinetdevice.NS3BaseWifiNetDevice(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

    +
    + +
    +
    +

    nepi.resources.ns3.ns3wifiphy module¶

    +
    +
    +class nepi.resources.ns3.ns3wifiphy.NS3BaseWifiPhy(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +channel[source]¶
    +
    + +
    +
    +device[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3wifiremotestationmanager module¶

    +
    +
    +class nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager(ec, guid)[source]¶
    +

    Bases: nepi.resources.ns3.ns3base.NS3Base

    +
    +
    +device[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.ns3wrapper module¶

    +
    +
    +class nepi.resources.ns3.ns3wrapper.NS3Wrapper(loglevel=20, enable_dump=False)[source]¶
    +

    Bases: object

    +
    +
    +allowed_types[source]¶
    +
    + +
    +
    +create(clazzname, *args)[source]¶
    +

    This method should be used to construct ns-3 objects that +do not have a TypeId (e.g. Values)

    +
    + +
    +
    +debuger[source]¶
    +
    + +
    +
    +factory(type_name, **kwargs)[source]¶
    +

    This method should be used to construct ns-3 objects +that have a TypeId and related introspection information

    +
    + +
    +
    +get(uuid, name)[source]¶
    +
    + +
    +
    +get_object(uuid)[source]¶
    +
    + +
    +
    +invoke(uuid, operation, *args, **kwargs)[source]¶
    +
    + +
    +
    +is_finished[source]¶
    +
    + +
    +
    +is_running[source]¶
    +
    + +
    +
    +is_started[source]¶
    +
    + +
    +
    +logger[source]¶
    +
    + +
    +
    +make_uuid()[source]¶
    +
    + +
    +
    +ns3[source]¶
    +
    + +
    +
    +replace_args(args)[source]¶
    +
    + +
    +
    +replace_kwargs(kwargs)[source]¶
    +
    + +
    +
    +set(uuid, name, value)[source]¶
    +
    + +
    +
    +shutdown()[source]¶
    +
    + +
    +
    +start()[source]¶
    +
    + +
    +
    +stop(time=None)[source]¶
    +
    + +
    + +
    +
    +nepi.resources.ns3.ns3wrapper.load_ns3_libraries()[source]¶
    +
    + +
    +
    +nepi.resources.ns3.ns3wrapper.load_ns3_module()[source]¶
    +
    + +
    +
    +

    nepi.resources.ns3.ns3wrapper_debug module¶

    +
    +
    +class nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger(enabled)[source]¶
    +

    Bases: object

    +
    +
    +dump_create(uuid, clazzname, args)[source]¶
    +
    + +
    +
    +dump_factory(uuid, type_name, kwargs)[source]¶
    +
    + +
    +
    +dump_get(uuid, name)[source]¶
    +
    + +
    +
    +dump_header()[source]¶
    +
    + +
    +
    +dump_invoke(newuuid, uuid, operation, args, kwargs)[source]¶
    +
    + +
    +
    +dump_set(uuid, name, value)[source]¶
    +
    + +
    +
    +dump_shutdown()[source]¶
    +
    + +
    +
    +dump_start()[source]¶
    +
    + +
    +
    +dump_stop(time=None)[source]¶
    +
    + +
    +
    +dump_to_script(command)[source]¶
    +
    + +
    +
    +enabled[source]¶
    +
    + +
    +
    +format_args(args)[source]¶
    +
    + +
    +
    +format_kwargs(kwargs)[source]¶
    +
    + +
    +
    +format_value(value)[source]¶
    +
    + +
    +
    +script_path[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.ns3.resource_manager_generator module¶

    +
    +
    +nepi.resources.ns3.resource_manager_generator.create_ns3_rms()[source]¶
    +
    + +
    +
    +nepi.resources.ns3.resource_manager_generator.select_base_class(ns3, tid)[source]¶
    +
    + +
    +
    +nepi.resources.ns3.resource_manager_generator.template_attributes(ns3, tid)[source]¶
    +
    + +
    +
    +nepi.resources.ns3.resource_manager_generator.template_traces(ns3, tid)[source]¶
    +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.omf.html b/doc/sphinx/_build/html/_layout/nepi.resources.omf.html new file mode 100644 index 00000000..c4353be0 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.omf.html @@ -0,0 +1,1597 @@ + + + + + + + + nepi.resources.omf package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +

    nepi.resources.omf package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.omf.application module¶

    +
    +
    +class nepi.resources.omf.application.OMFApplication(ec, guid)[source]¶
    +

    Bases: nepi.resources.omf.omf_resource.OMFResource

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • ec (ExperimentController) – The Experiment controller
    • +
    • guid (int) – guid of the RM
    • +
    +
    +
    + +
    +
    +add_set_hook()[source]¶
    +

    Initialize the hooks for OMF 5.4 only

    +
    + +
    +
    +check_deploy(cid)[source]¶
    +

    Check, through the mail box in the parser, +if the confirmation of the creation has been received

    + +++ + + + +
    Parameters:cid – the id of the original message
    +
    + +
    +
    +check_release(cid)[source]¶
    +

    Check, through the mail box in the parser, +if the confirmation of the release has been received

    + +++ + + + +
    Parameters:cid – the id of the original message
    +
    + +
    +
    +check_start(uid)[source]¶
    +

    Check, through the mail box in the parser, +if the confirmation of the start has been received

    + +++ + + + +
    Parameters:uid – the id of the original message
    +
    + +
    +
    +do_deploy()[source]¶
    +

    Deploy the RM. It means nothing special for an application +for now (later it will be upload sources, ...) +It becomes DEPLOYED after the topic for the application has been created

    +
    + +
    +
    +do_release()[source]¶
    +

    Clean the RM at the end of the experiment and release the API.

    +
    + +
    +
    +do_start()[source]¶
    +

    Start the RM. It means : Send Xmpp Message Using OMF protocol +to execute the application.

    +
    + +
    +
    +do_stop()[source]¶
    +

    Stop the RM. It means : Send Xmpp Message Using OMF protocol to +kill the application. +State is set to STOPPED after the message is sent.

    +
    + +
    +
    +exp_id[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +stdin_hook(old_value, new_value)[source]¶
    +

    Set a hook to the stdin attribute in order to send a message at each time +the value of this parameter is changed. Used ofr OMF 5.4 only

    +
    + +
    +
    +trace(name, attr='all', block=512, offset=0)[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +

    Check if the connection with the guid in parameter is possible. +Only meaningful connections are allowed.

    + +++ + + + + + +
    Parameters:guid (int) – Guid of RM it will be connected
    Return type:Boolean
    +
    + +
    + +
    +
    +

    nepi.resources.omf.channel module¶

    +
    +
    +class nepi.resources.omf.channel.OMFChannel(ec, guid)[source]¶
    +

    Bases: nepi.resources.omf.omf_resource.OMFResource

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • ec (ExperimentController) – The Experiment controller
    • +
    • guid (int) – guid of the RM
    • +
    • creds (dict) – Credentials to communicate with the rm (XmppClient for OMF)
    • +
    +
    +
    + +
    +
    +ChannelToFreq = {'11': '2462', '10': '2457', '13': '2472', '12': '2467', '1': '2412', '3': '2422', '2': '2417', '5': '2432', '4': '2427', '7': '2442', '6': '2437', '9': '2452', '8': '2447'}¶
    +
    + +
    +
    +do_deploy()[source]¶
    +

    Deploy the RM. It means : Get the xmpp client and send messages +using OMF 5.4 or 6 protocol to configure the channel.

    +
    + +
    +
    +do_release()[source]¶
    +

    Clean the RM at the end of the experiment and release the API

    +
    + +
    +
    +exp_id[source]¶
    +
    + +
    +
    +get_frequency(channel)[source]¶
    +

    Returns the frequency of a specific channel number

    +
    + +
    +
    +valid_connection(guid)[source]¶
    +

    Check if the connection with the guid in parameter is possible. +Only meaningful connections are allowed.

    + +++ + + + + + +
    Parameters:guid (int) – Guid of the current RM
    Return type:Boolean
    +
    + +
    + +
    +
    +

    nepi.resources.omf.interface module¶

    +
    +
    +class nepi.resources.omf.interface.OMFWifiInterface(ec, guid)[source]¶
    +

    Bases: nepi.resources.omf.omf_resource.OMFResource

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • ec (ExperimentController) – The Experiment controller
    • +
    • guid (int) – guid of the RM
    • +
    +
    +
    + +
    +
    +channel[source]¶
    +
    + +
    +
    +check_deploy(cid)[source]¶
    +

    Check, through the mail box in the parser, +if the confirmation of the creation has been received

    + +++ + + + +
    Parameters:cid – the id of the original message
    +
    + +
    +
    +check_release(cid)[source]¶
    +

    Check, through the mail box in the parser, +if the confirmation of the release has been received

    + +++ + + + +
    Parameters:cid – the id of the original message
    +
    + +
    +
    +configure_iface()[source]¶
    +

    Configure the interface without the ip

    +
    + +
    +
    +configure_ip()[source]¶
    +

    Configure the ip of the interface

    +

    CELL ID shraing problem. By putting th ip at the end of the configuration, +each node use the same channel and can then share the same CELL ID. +In the second case, the channel is defined at the end and the node don’t +share a common CELL ID and can not communicate.

    +
    + +
    +
    +configure_on_omf5()[source]¶
    +

    Method to configure the wifi interface when OMF 5.4 is used.

    +
    + +
    +
    +configure_on_omf6()[source]¶
    +

    Method to configure the wifi interface when OMF 6 is used.

    +
    + +
    +
    +do_deploy()[source]¶
    +

    Deploy the RM. It means : Get the xmpp client and send messages +using OMF 5.4 or 6 protocol to configure the interface.

    +
    + +
    +
    +do_release()[source]¶
    +

    Clean the RM at the end of the experiment and release the API

    +
    + +
    +
    +exp_id[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +

    Check if the connection with the guid in parameter is possible. +Only meaningful connections are allowed.

    + +++ + + + + + +
    Parameters:guid (int) – Guid of the current RM
    Return type:Boolean
    +
    + +
    + +
    +
    +

    nepi.resources.omf.messages_5_4 module¶

    +
    +
    +class nepi.resources.omf.messages_5_4.MessageHandler(sliceid, expid)[source]¶
    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • sliceid – Slice Name (= Xmpp Slice)
    • +
    • expid (str) – Experiment ID (= Xmpp User)
    • +
    +
    +
    + +
    +

    Note

    +

    This class is used only for OMF 5.4 Protocol and is going to become unused

    +
    +
    +
    +alias_function(name, target)[source]¶
    +

    Build an Alias Message

    + +++ + + + +
    Parameters:
      +
    • name (str) – Name of the new alias
    • +
    • target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
    • +
    +
    +
    + +
    +
    +configure_function(target, value, path)[source]¶
    +

    Build a Configure Message

    + +++ + + + +
    Parameters:
      +
    • target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
    • +
    • value (int) – guid of the RM
    • +
    • path (dict) – Path of the element to configure (ex : net/w0/channel)
    • +
    +
    +
    + +
    +
    +enroll_function(enrollkey, image, index, target)[source]¶
    +

    Build an Enroll Message

    + +++ + + + +
    Parameters:
      +
    • enrollkey (str) – Type of enrollment (= 1)
    • +
    • image (str) – Image (= * when all the nodes are concerned)
    • +
    • index (str) – Index (= 1 in general)
    • +
    • target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
    • +
    +
    +
    + +
    +
    +execute_function(target, appid, cmdlineargs, path, env)[source]¶
    +

    Build an Execute Message

    + +++ + + + +
    Parameters:
      +
    • target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
    • +
    • appid (str) – Application id
    • +
    • cmdlineargs (str) – Arguments of the application
    • +
    • path (str) – Path of the application
    • +
    • env (str) – Environment variables
    • +
    +
    +
    + +
    +
    +exit_function(target, appid)[source]¶
    +

    Build an Exit Message

    + +++ + + + +
    Parameters:
      +
    • target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
    • +
    • appid (str) – Application id (ex : vlc#1)
    • +
    +
    +
    + +
    +
    +log_function(level, logger, level_name, data)[source]¶
    +

    Build a Log Message

    + +++ + + + +
    Parameters:
      +
    • level (str) – Level of logging
    • +
    • logger (str) – Element publishing the log
    • +
    • level_name (str) – Name of the level (ex : INFO)
    • +
    • data (str) – Content to publish
    • +
    +
    +
    + +
    +
    +newexp_function(experimentid, address)[source]¶
    +

    Build a NewExp Message

    + +++ + + + +
    Parameters:
      +
    • experimentid (str) – Id of the new experiment
    • +
    • address (str) – Adress of the destination set of nodes
    • +
    +
    +
    + +
    +
    +noop_function(target)[source]¶
    +

    Build a Noop Message

    + +++ + + + +
    Parameters:target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
    +
    + +
    +
    +stdin_function(target, value, appid)[source]¶
    +

    Build an Execute Message

    + +++ + + + +
    Parameters:
      +
    • value (str) – parameter that go in the stdin
    • +
    • target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
    • +
    • appid (str) – Application id
    • +
    +
    +
    + +
    + +
    +
    +

    nepi.resources.omf.messages_6 module¶

    +
    +
    +class nepi.resources.omf.messages_6.MessageHandler[source]¶
    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • sliceid – Slice Name (= Xmpp Slice)
    • +
    • expid (str) – Experiment ID (= Xmpp User)
    • +
    +
    +
    + +
    +

    Note

    +

    This class is used only for OMF 5.4 Protocol and is going to become unused

    +
    +
    +
    +configure_function(msg_id, src, timestamp, props=None, guards=None)[source]¶
    +

    Build a configure message

    + +++ + + + +
    Parameters:
      +
    • msg_id (str) – Id of the message
    • +
    • src (str) – Src node that send the message (jabber source)
    • +
    • timestamp (str) – Unix Timestamp
    • +
    • props (list) – List of properties
    • +
    • guards (list) – list of guards (assertions for properties)
    • +
    +
    +
    + +
    +
    +create_function(msg_id, src, rtype, timestamp, props=None, guards=None)[source]¶
    +

    Build a create message

    + +++ + + + +
    Parameters:
      +
    • msg_id (str) – Id of the message
    • +
    • src (str) – Src node that send the message (jabber source)
    • +
    • rtype (str) – Type of the object
    • +
    • timestamp (str) – Unix Timestamp
    • +
    • props (list) – List of properties
    • +
    • guards (list) – list of guards (assertions for properties)
    • +
    +
    +
    + +
    +
    +release_function(msg_id, src, timestamp, res_id=None, props=None, guards=None)[source]¶
    +

    Build a release message

    + +++ + + + +
    Parameters:
      +
    • msg_id (str) – Id of the message
    • +
    • src (str) – Src node that send the message (jabber source)
    • +
    • timestamp (str) – Unix Timestamp
    • +
    • res_id (str) – Id of the release resource
    • +
    • props (list) – List of properties
    • +
    • guards (list) – list of guards (assertions for properties)
    • +
    +
    +
    + +
    +
    +request_function(msg_id, src, timestamp, props=None, guards=None)[source]¶
    +

    Build a request message

    + +++ + + + +
    Parameters:
      +
    • msg_id (str) – Id of the message
    • +
    • src (str) – Src node that send the message (jabber source)
    • +
    • timestamp (str) – Unix Timestamp
    • +
    • props (list) – List of properties
    • +
    • guards (list) – list of guards (assertions for properties)
    • +
    +
    +
    + +
    + +
    +
    +

    nepi.resources.omf.node module¶

    +
    +
    +class nepi.resources.omf.node.OMFNode(ec, guid)[source]¶
    +

    Bases: nepi.resources.omf.omf_resource.OMFResource

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • ec (ExperimentController) – The Experiment controller
    • +
    • guid (int) – guid of the RM
    • +
    • creds (dict) – Credentials to communicate with the rm (XmppClient for OMF)
    • +
    +
    +
    + +
    +
    +do_deploy()[source]¶
    +

    Deploy the RM. It means : Send Xmpp Message Using OMF protocol +to enroll the node into the experiment.

    +
    + +
    +
    +do_release()[source]¶
    +

    Clean the RM at the end of the experiment by unenrolling +the node from the topic

    +
    + +
    +
    +exp_id[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +

    Check if the connection with the guid in parameter is possible. +Only meaningful connections are allowed.

    + +++ + + + + + +
    Parameters:guid (int) – Guid of the current RM
    Return type:Boolean
    +
    + +
    + +
    +
    +

    nepi.resources.omf.omf5_api module¶

    +
    +
    +class nepi.resources.omf.omf5_api.OMF5API(host, slice, port, password, xmpp_root=None, exp_id=None)[source]¶
    +

    Bases: nepi.util.logger.Logger

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • host (str) – Xmpp Server
    • +
    • slice (str) – Xmpp Slice
    • +
    • port (str) – Xmpp Port
    • +
    • password (str) – Xmpp password
    • +
    • xmpp_root (str) – Root of the Xmpp Topic Architecture
    • +
    +
    +
    + +
    +

    Note

    +

    This class is the implementation of an OMF 5.4 API. +Since the version 5.4.1, the Topic Architecture start with OMF_5.4 +instead of OMF used for OMF5.3

    +
    +
    +
    +configure(hostname, attribute, value)[source]¶
    +

    Configure attribute on the node

    + +++ + + + +
    Parameters:
      +
    • hostname (str) – Full hrn of the node
    • +
    • attribute (str) – Attribute that need to be configured ( +often written as /net/wX/attribute, with X the interface number)
    • +
    • value (str) – Value of the attribute
    • +
    +
    +
    + +
    +
    +delete(hostname)[source]¶
    +

    Delete the topic corresponding to the hostname for this session

    + +++ + + + +
    Parameters:hostname (str) – Full hrn of the node
    +
    + +
    +
    +disconnect()[source]¶
    +

    Delete the session and logger topics. Then disconnect

    +
    + +
    +
    +enroll_host(hostname)[source]¶
    +
    +
    Create and Subscribe to the session topic and the resources
    +
    corresponding to the hostname
    +
    + +++ + + + +
    Parameters:hostname (str) – Full hrn of the node
    +
    + +
    +
    +execute(hostname, app_id, arguments, path, env)[source]¶
    +

    Execute command on the node

    + +++ + + + +
    Parameters:
      +
    • hostname (str) – Full hrn of the node
    • +
    • app_id (str) – Application Id (Any id that represents in a unique +way the application)
    • +
    • arguments (str) – Arguments of the application
    • +
    • path (str) – Path of the application
    • +
    • env (str) – Environnement values for the application
    • +
    +
    +
    + +
    +
    +exit(hostname, app_id)[source]¶
    +

    Kill an application started with OMF

    + +++ + + + +
    Parameters:
      +
    • hostname (str) – Full hrn of the node
    • +
    • app_id (str) – Application Id of the application you want to stop
    • +
    +
    +
    + +
    +
    +release(hostname)[source]¶
    +

    Delete the session and logger topics. Then disconnect

    +
    + +
    +
    +send_stdin(hostname, value, app_id)[source]¶
    +

    Send to the stdin of the application the value

    + +++ + + + +
    Parameters:
      +
    • hostname (str) – Full hrn of the node
    • +
    • appid (str) – Application Id (Any id that represents in a unique +way the application)
    • +
    • value (str) – parameter to execute in the stdin of the application
    • +
    +
    +
    + +
    + +
    +
    +

    nepi.resources.omf.omf6_api module¶

    +
    +
    +class nepi.resources.omf.omf6_api.OMF6API(server, user='nepi', port='5222', password='1234', exp_id=None)[source]¶
    +

    Bases: nepi.util.logger.Logger

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • server (str) – Xmpp Server
    • +
    • user (str) – Xmpp User
    • +
    • port (str) – Xmpp Port
    • +
    • password (str) – Xmpp password
    • +
    • xmpp_root (str) – Root of the Xmpp Topic Architecture
    • +
    +
    +
    + +
    +

    Note

    +

    This class is the implementation of an OMF 5.4 API. +Since the version 5.4.1, the Topic Architecture start with OMF_5.4 +instead of OMF used for OMF5.3

    +
    +
    +
    +check_mailbox(itype, attr)[source]¶
    +

    Check the mail box

    + +++ + + + +
    Parameters:
      +
    • itype (str) – type of mail
    • +
    • attr (str) – value wanted
    • +
    +
    +
    + +
    +
    +check_ready(xmpp)[source]¶
    +
    + +
    +
    +create_and_enroll_topic(topic)[source]¶
    +
    +
    Create and Subscribe to the session topic and the resources
    +
    corresponding to the hostname
    +
    + +++ + + + +
    Parameters:hostname (str) – Full hrn of the node
    +
    + +
    +
    +disconnect()[source]¶
    +

    Delete the session and logger topics. Then disconnect

    +
    + +
    +
    +enroll_topic(topic)[source]¶
    +

    Create and Subscribe to the session topic and the resources +corresponding to the hostname

    +
    + +
    +
    +frcp_configure(topic, props=None, guards=None)[source]¶
    +

    Publish a configure message

    +
    + +
    +
    +frcp_create(msg_id, topic, rtype, props=None, guards=None)[source]¶
    +

    Publish a create message

    +
    + +
    +
    +frcp_inform(topic, cid, itype)[source]¶
    +

    Publish an inform message

    +
    + +
    +
    +frcp_release(msg_id, parent, child, res_id=None, props=None, guards=None)[source]¶
    +

    Publish a release message

    +
    + +
    +
    +frcp_request(topic, props=None, guards=None)[source]¶
    +

    Execute command on the node

    +
    + +
    +
    +unenroll_topic(topic)[source]¶
    +

    Create and Subscribe to the session topic and the resources +corresponding to the hostname

    +
    + +
    + +
    +
    +

    nepi.resources.omf.omf6_parser module¶

    +
    +
    +class nepi.resources.omf.omf6_parser.OMF6Parser[source]¶
    +

    Bases: nepi.util.logger.Logger

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • jid (str) – Jabber Id (= Xmpp Slice + Date)
    • +
    • password (str) – Jabber Password (= Xmpp Password)
    • +
    +
    +
    + +
    +

    Note

    +

    This class is an XMPP Client with customized method

    +
    +
    +
    +check_mailbox(itype, attr)[source]¶
    +

    Check the mail box

    + +++ + + + +
    Parameters:
      +
    • itype (str) – type of mail
    • +
    • attr (str) – value wanted
    • +
    +
    +
    + +
    +
    +handle(iq)[source]¶
    +

    Check the mail box

    + +++ + + + +
    Parameters:iq – message received
    +
    + +
    +
    +init_mailbox()[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.omf.omf_api_factory module¶

    +
    +
    +class nepi.resources.omf.omf_api_factory.OMFAPIFactory[source]¶
    +

    Bases: object

    +
    +

    Note

    +

    It allows the different RM to use the same xmpp client if they use +the same credentials. For the moment, it is focused on XMPP.

    +
    +
    +
    +classmethod create_api(version, server, user, port, password, exp_id)[source]¶
    +

    Create an OMF API if this one doesn’t exist yet with this credentials

    + +++ + + + +
    Parameters:
      +
    • version (str) – OMF Version. Either 5 or 6
    • +
    • server (str) – Xmpp Server Adress
    • +
    • user (str) – Xmpp User
    • +
    • port (str) – Xmpp Port (Default : 5222)
    • +
    • password (str) – Xmpp Password
    • +
    • exp_id (str) – Id of the experiment
    • +
    +
    +
    + +
    +
    +classmethod get_api(version, server, user, port, password, exp_id=None)[source]¶
    +

    Get an OMF Api

    + +++ + + + +
    Parameters:
      +
    • version (str) – OMF Version. Either 5 or 6
    • +
    • server (str) – Xmpp Server Adress
    • +
    • user (str) – Xmpp User
    • +
    • port (str) – Xmpp Port (Default : 5222)
    • +
    • password (str) – Xmpp Password
    • +
    • exp_id (str) – Id of the experiment
    • +
    +
    +
    + +
    +
    +lock = <thread.lock object at 0x7f028fc193b0>¶
    +
    + +
    +
    +classmethod release_api(version, server, user, port, password, exp_id=None)[source]¶
    +

    Release an OMF API with this credentials

    + +++ + + + +
    Parameters:
      +
    • version (str) – OMF Version. Either 5 or 6
    • +
    • server (str) – Xmpp Server Adress
    • +
    • user (str) – Xmpp User
    • +
    • port (str) – Xmpp Port (Default : 5222)
    • +
    • password (str) – Xmpp Password
    • +
    • exp_id (str) – Id of the experiment
    • +
    +
    +
    + +
    + +
    +
    +

    nepi.resources.omf.omf_client module¶

    +
    +
    +class nepi.resources.omf.omf_client.BaseOMFClient(jid, password, ssl=False, plugin_config={}, plugin_whitelist=[], escape_quotes=True, sasl_mech=None)[source]¶
    +

    Bases: sleekxmpp.clientxmpp.ClientXMPP

    +
    + +
    +
    +class nepi.resources.omf.omf_client.OMFClient(jid, password)[source]¶
    +

    Bases: nepi.resources.omf.omf_client.BaseOMFClient, nepi.util.logger.Logger

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • jid (str) – Jabber Id (= Xmpp Slice + Date)
    • +
    • password (str) – Jabber Password (= Xmpp Password)
    • +
    +
    +
    + +
    +

    Note

    +

    This class is an XMPP Client with customized method

    +
    +
    +
    +check_mailbox(itype, attr)[source]¶
    +

    Check the mail box

    + +++ + + + +
    Parameters:
      +
    • itype (str) – type of mail
    • +
    • attr (str) – value wanted
    • +
    +
    +
    + +
    +
    +create(node)[source]¶
    +

    Create the topic corresponding to the node

    + +++ + + + +
    Parameters:node (str) – Name of the topic, corresponding to the node (ex : omf.plexus.wlab17)
    +
    + +
    +
    +delete(node)[source]¶
    +

    Delete the topic corresponding to the node

    + +++ + + + +
    Parameters:node (str) – Name of the topic, corresponding to the node (ex : omf.plexus.wlab17)
    +
    + +
    +
    +get(data)[source]¶
    +

    Get the item

    + +++ + + + +
    Parameters:data (str) – data from which the items will be get back
    +
    + +
    +
    +handle_omf_message(iq)[source]¶
    +

    Handle published/received message

    + +++ + + + +
    Parameters:iq (Iq Stanza) – Stanzas that is currently published/received
    +
    + +
    +
    +nodes()[source]¶
    +

    Get all the nodes of the Xmppp Server.

    +
    + +
    +
    +publish(data, node)[source]¶
    +

    Publish the data to the corresponding topic

    + +++ + + + +
    Parameters:
      +
    • data (str) – Data that will be published
    • +
    • node (str) – Name of the topic
    • +
    +
    +
    + +
    +
    +purge()[source]¶
    +

    Purge the information in the server

    +
    + +
    +
    +ready[source]¶
    +

    Check if the client is ready

    +
    + +
    +
    +register(iq)[source]¶
    +

    Register to the Xmppp Server. This function is called directly by the sleekXmpp library

    +
    + +
    +
    +retract(data)[source]¶
    +

    Retract the item

    + +++ + + + +
    Parameters:data (str) – data from which the item will be retracted
    +
    + +
    +
    +start(event)[source]¶
    +

    Send presence to the Xmppp Server. This function is called directly by the sleekXmpp library

    +
    + +
    +
    +subscribe(node)[source]¶
    +

    Subscribe to a topic

    + +++ + + + +
    Parameters:node (str) – Name of the topic
    +
    + +
    +
    +subscriptions()[source]¶
    +

    Get all the subscriptions of the Xmppp Server.

    +
    + +
    +
    +unregister()[source]¶
    +

    Unregister from the Xmppp Server.

    +
    + +
    +
    +unsubscribe(node)[source]¶
    +

    Unsubscribe to a topic

    + +++ + + + +
    Parameters:node (str) – Name of the topic
    +
    + +
    + +
    +
    +

    nepi.resources.omf.omf_resource module¶

    +
    +
    +class nepi.resources.omf.omf_resource.OMFResource(ec, guid)[source]¶
    +

    Bases: nepi.execution.resource.ResourceManager

    +

    Generic resource gathering XMPP credential information and common methods +for OMF nodes, channels, applications, etc.

    +
    + +
    +
    +class nepi.resources.omf.omf_resource.ResourceGateway[source]¶
    +

    Dictionary used to set OMF gateway depending on Testbed information.

    +
    +
    +AMtoGateway = {'nitlab.inf.uth.gr': 'nitlab.inf.uth.gr', 'nicta': '??.??.??', 'am.wilab2.ilabt.iminds.be': 'ops.wilab2.ilabt.iminds.be'}¶
    +
    + +
    +
    +TestbedtoGateway = {'wilabt': 'ops.wilab2.ilabt.iminds.be', 'nicta': '??.??.??', 'nitos': 'nitlab.inf.uth.gr'}¶
    +
    + +
    + +
    +
    +

    nepi.resources.omf.wilabt_node module¶

    +
    +
    +class nepi.resources.omf.wilabt_node.WilabtSfaNode(ec, guid)[source]¶
    +

    Bases: nepi.resources.omf.node.OMFNode

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_discover()[source]¶
    +

    Based on the attributes defined by the user, discover the suitable +node for provision.

    +
    + +
    +
    +do_provision()[source]¶
    +

    Add node to user’s slice and verifing that the node is functioning +correctly. Check ssh, omf rc running, hostname, file system.

    +
    + +
    +
    +do_release()[source]¶
    +
    + +
    +
    +execute(command, sudo=False, env=None, tty=False, forward_x11=False, retry=3, connect_timeout=30, strict_host_checking=False, persistent=True, blocking=True)[source]¶
    +

    Notice that this invocation will block until the +execution finishes. If this is not the desired behavior, +use ‘run’ instead.

    +
    + +
    +
    +fail_discovery()[source]¶
    +
    + +
    +
    +fail_node_not_alive(host=None)[source]¶
    +
    + +
    +
    +fail_node_not_available(host)[source]¶
    +
    + +
    +
    +fail_not_enough_nodes()[source]¶
    +
    + +
    +
    +fail_sfaapi()[source]¶
    +
    + +
    +
    +sfaapi[source]¶
    +

    Property to instanciate the SFA API based in sfi client. +For each SFA method called this instance is used.

    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.html b/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.html new file mode 100644 index 00000000..8477bca4 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.html @@ -0,0 +1,629 @@ + + + + + + + + nepi.resources.planetlab package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +

    nepi.resources.planetlab package¶

    + +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.planetlab.node module¶

    +
    +
    +class nepi.resources.planetlab.node.PlanetlabNode(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.node.LinuxNode

    +
    +
    +do_discover()[source]¶
    +

    Based on the attributes defined by the user, discover the suitable +nodes for provision.

    +
    + +
    +
    +do_provision()[source]¶
    +

    Add node to user’s slice after verifing that the node is functioning +correctly

    +
    + +
    +
    +do_release()[source]¶
    +
    + +
    +
    +fail_discovery()[source]¶
    +
    + +
    +
    +fail_node_not_alive(hostname=None)[source]¶
    +
    + +
    +
    +fail_node_not_available(hostname)[source]¶
    +
    + +
    +
    +fail_not_enough_nodes()[source]¶
    +
    + +
    +
    +fail_plapi()[source]¶
    +
    + +
    +
    +lock = <thread.lock object at 0x7f028fc19a70>¶
    +
    + +
    +
    +plapi[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.planetlab.plcapi module¶

    +
    +
    +class nepi.resources.planetlab.plcapi.PLCAPI(username, password, hostname, urlpattern, ec, proxy, session_key=None, local_peer='PLE')[source]¶
    +

    Bases: object

    +
    +
    +add_slice_nodes(slicename, nodes)[source]¶
    +
    + +
    +
    +api[source]¶
    +
    + +
    +
    +blacklist_host(node_id)[source]¶
    +
    + +
    +
    +blacklisted()[source]¶
    +
    + +
    +
    +delete_slice_node(slice_id_or_name, node_id_or_hostname)[source]¶
    +
    + +
    +
    +finish_multicall()[source]¶
    +
    + +
    +
    +get_interfaces(interface_id_or_ip=None, fields=None, **kw)[source]¶
    +
    + +
    +
    +get_node_flavour(node)[source]¶
    +

    Returns detailed information on a given node’s flavour, +i.e. its base installation.

    +

    This depends on the global PLC settings in the PLC_FLAVOUR area, +optionnally overridden by any of the following tags if set on that node: +‘arch’, ‘pldistro’, ‘fcdistro’, ‘deployment’, ‘extensions’

    +

    Params:

    +
    +
      +
    • +
      node : int or string
      +
        +
      • int, Node identifier
      • +
      • string, Fully qualified hostname
      • +
      +
      +
      +
    • +
    +
    +

    Returns:

    +
    +
    +
    struct
    +
      +
    • extensions : array of string, extensions to add to the base install
    • +
    • fcdistro : string, the fcdistro this node should be based upon
    • +
    • nodefamily : string, the nodefamily this node should be based upon
    • +
    • plain : boolean, use plain bootstrapfs image if set (for tests)
    • +
    +
    +
    +
    +
    + +
    +
    +get_node_info(node_id)[source]¶
    +
    + +
    +
    +get_node_tags(node_tag_id=None, fields=None, **kw)[source]¶
    +
    + +
    +
    +get_nodes(node_id_or_name=None, fields=None, **kw)[source]¶
    +

    Returns an array of structs containing details about nodes. +If node_id_or_name is specified and is an array of node identifiers +or hostnames, or the filters keyword argument with struct of node +attributes, or node attributes by keyword argument, +only nodes matching the filter will be returned.

    +

    If fields is specified, only the specified details will be returned. +NOTE that if fields is unspecified, the complete set of native fields are +returned, which DOES NOT include tags at this time.

    +

    Some fields may only be viewed by admins.

    +

    Special params:

    +
    +

    fields: an optional list of fields to retrieve. The default is all.

    +
    +
    filters: an optional mapping with custom filters, which is the only
    +
    way to support complex filters like negation and numeric comparisons.
    +
    peer: a string (or sequence of strings) with the name(s) of peers
    +
    to filter - or None for local nodes.
    +
    +
    +
    + +
    +
    +get_slice_id(slicename)[source]¶
    +
    + +
    +
    +get_slice_nodes(slicename)[source]¶
    +
    + +
    +
    +get_slice_tags(slice_tag_id=None, fields=None, **kw)[source]¶
    +
    + +
    +
    +get_slice_vnet_sys_tag(slicename)[source]¶
    +
    + +
    +
    +get_slices(slice_id_or_name=None, fields=None, **kw)[source]¶
    +
    + +
    +
    +mcapi[source]¶
    +
    + +
    +
    +network_types[source]¶
    +
    + +
    +
    +peer_map[source]¶
    +
    + +
    +
    +release()[source]¶
    +
    + +
    +
    +reserve_host(node_id)[source]¶
    +
    + +
    +
    +reserved()[source]¶
    +
    + +
    +
    +start_multicall()[source]¶
    +
    + +
    +
    +test()[source]¶
    +
    + +
    +
    +unblacklist_host(node_id)[source]¶
    +
    + +
    +
    +unreserve_host(node_id)[source]¶
    +
    + +
    +
    +update_slice(slice_id_or_name, **kw)[source]¶
    +
    + +
    + +
    +
    +class nepi.resources.planetlab.plcapi.PLCAPIFactory[source]¶
    +

    Bases: object

    +
    +

    Note

    +

    It allows PlanetLab RMs sharing a same slice, to use a same plcapi instance, +and to sincronize blacklisted and reserved hosts.

    +
    +
    +
    +classmethod create_api(pl_user, pl_pass, pl_host, pl_ptn, ec, proxy=None)[source]¶
    +

    Create an PLCAPI instance

    + +++ + + + +
    Parameters:
      +
    • pl_user (str) – Planelab user name (used for web login)
    • +
    • pl_pass (str) – Planetlab password (used for web login)
    • +
    • pl_host (str) – Planetlab registry host (e.g. “www.planet-lab.eu”)
    • +
    • pl_ptn (str) – XMLRPC service pattern (e.g. https://%(hostname)s:443/PLCAPI/)
    • +
    • proxy – Proxy service url
    • +
    +
    +
    + +
    +
    +classmethod get_api(pl_user, pl_pass, pl_host, pl_ptn, ec, proxy=None)[source]¶
    +

    Get existing PLCAPI instance

    + +++ + + + +
    Parameters:
      +
    • pl_user (str) – Planelab user name (used for web login)
    • +
    • pl_pass (str) – Planetlab password (used for web login)
    • +
    • pl_host (str) – Planetlab registry host (e.g. “www.planet-lab.eu”)
    • +
    • pl_ptn (str) – XMLRPC service pattern (e.g. https://%(hostname)s:443/PLCAPI/)
    • +
    • proxy – Proxy service url
    • +
    +
    +
    + +
    + +
    +
    +

    nepi.resources.planetlab.sfa_node module¶

    +
    +
    +class nepi.resources.planetlab.sfa_node.PlanetlabSfaNode(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.node.LinuxNode

    +
    +
    +do_discover()[source]¶
    +

    Based on the attributes defined by the user, discover the suitable +nodes for provision.

    +
    + +
    +
    +do_provision()[source]¶
    +

    Add node to user’s slice and verifing that the node is functioning +correctly. Check ssh, file system.

    +
    + +
    +
    +do_release()[source]¶
    +
    + +
    +
    +fail_discovery()[source]¶
    +
    + +
    +
    +fail_node_not_alive(hostname=None)[source]¶
    +
    + +
    +
    +fail_node_not_available(hostname)[source]¶
    +
    + +
    +
    +fail_not_enough_nodes()[source]¶
    +
    + +
    +
    +fail_sfaapi()[source]¶
    +
    + +
    +
    +sfaapi[source]¶
    +

    Property to instanciate the SFA API based in sfi client. +For each SFA method called this instance is used.

    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    nepi.resources.planetlab.tap module¶

    +
    +
    +class nepi.resources.planetlab.tap.PlanetlabTap(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.tap.LinuxTap

    +
    +
    +gre_connect(remote_endpoint, connection_app_home, connection_run_home)[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +upload_sources()[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    +
    +vif_name_file[source]¶
    +
    + +
    +
    +wait_vif_name(exec_run_home=None)[source]¶
    +

    Waits until the vif_name file for the command is generated, +and returns the vif_name for the device

    +
    + +
    + +
    +
    +

    nepi.resources.planetlab.tun module¶

    +
    +
    +class nepi.resources.planetlab.tun.PlanetlabTun(ec, guid)[source]¶
    +

    Bases: nepi.resources.planetlab.tap.PlanetlabTap

    +
    + +
    +
    +

    nepi.resources.planetlab.vroute module¶

    +
    +
    +class nepi.resources.planetlab.vroute.PlanetlabVroute(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +do_deploy()[source]¶
    +
    + +
    +
    +do_release()[source]¶
    +
    + +
    +
    +do_start()[source]¶
    +
    + +
    +
    +do_stop()[source]¶
    +
    + +
    +
    +node[source]¶
    +
    + +
    +
    +tap[source]¶
    +
    + +
    +
    +upload_sources()[source]¶
    +
    + +
    +
    +upload_start_command()[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +
    + +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.ns3.html b/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.ns3.html new file mode 100644 index 00000000..9f3b72ff --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.ns3.html @@ -0,0 +1,153 @@ + + + + + + + + nepi.resources.planetlab.ns3 package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + +
    +
    +
    +
    + +
    +

    nepi.resources.planetlab.ns3 package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.planetlab.ns3.fdudptunnel module¶

    +
    +
    +class nepi.resources.planetlab.ns3.fdudptunnel.PlanetlabNs3FdUdpTunnel(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel

    +
    +
    +get_endpoints()[source]¶
    +

    Returns the list of RM that are endpoints to the tunnel

    +
    + +
    + +
    + +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.openvswitch.html b/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.openvswitch.html new file mode 100644 index 00000000..714703b5 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.openvswitch.html @@ -0,0 +1,321 @@ + + + + + + + + nepi.resources.planetlab.openvswitch package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + +
    +
    +
    +
    + +
    +

    nepi.resources.planetlab.openvswitch package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.resources.planetlab.openvswitch.ovs module¶

    +
    +
    +class nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • ec (ExperimentController) – The Experiment controller
    • +
    • guid (int) – guid of the RM
    • +
    +
    +
    + +
    +
    +assign_controller()[source]¶
    +

    Set the controller IP

    +
    + +
    +
    +check_sliver_ovs()[source]¶
    +

    Check if sliver-ovs exists. If it does not exist, the execution is stopped

    +
    + +
    +
    +create_bridge()[source]¶
    +

    Create the bridge/switch and check error during SSH connection

    +
    + +
    +
    +do_deploy()[source]¶
    +

    Deploy the OVS Switch : Turn on the server, create the bridges +and assign the controller

    +
    + +
    +
    +do_provision()[source]¶
    +
    + +
    +
    +do_release()[source]¶
    +

    Delete the bridge and close the server.

    +
    +
    +

    to be released before releasing itself

    +
    + +
    +
    +node[source]¶
    +

    Node wthat run the switch

    +
    + +
    +
    +ovs_status()[source]¶
    +

    Print the status of the bridge

    +
    + +
    +
    +servers_on()[source]¶
    +

    Start the openvswitch servers and check it

    +
    + +
    +
    +valid_connection(guid)[source]¶
    +

    Check if the connection with the guid in parameter is possible. Only meaningful connections are allowed.

    + +++ + + + + + +
    Parameters:guid (int) – Guid of the current RM
    Return type:Boolean
    +
    + +
    + +
    +
    +

    nepi.resources.planetlab.openvswitch.ovsport module¶

    +
    +
    +class nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort(ec, guid)[source]¶
    +

    Bases: nepi.resources.linux.application.LinuxApplication

    +
    +
    +Class Args :
    +
    +++ + + + +
    Parameters:
      +
    • ec (ExperimentController) – The Experiment controller
    • +
    • guid (int) – guid of the RM
    • +
    +
    +
    + +
    +
    +check_status()[source]¶
    +
    + +
    +
    +create_port()[source]¶
    +

    Create the desired port

    +
    + +
    +
    +do_deploy()[source]¶
    +

    Deploy the OVS port after the OVS Switch

    +
    + +
    +
    +do_provision()[source]¶
    +
    + +
    +
    +do_release()[source]¶
    +

    Delete the port on the OVSwitch. It needs to wait for the tunnel +to be released.

    +
    + +
    +
    +establish_udp_connection(remote_endpoint, connection_app_home, connection_run_home, port)[source]¶
    +
    + +
    +
    +initiate_udp_connection(remote_endpoint, connection_app_home, connection_run_home, cipher, cipher_key, bwlimit, txqueuelen)[source]¶
    +

    Get the local_endpoint of the port

    +
    + +
    +
    +node[source]¶
    +

    Node that run the switch and the ports

    +
    + +
    +
    +ovsswitch[source]¶
    +

    Switch where the port is created

    +
    + +
    +
    +port_number[source]¶
    +
    + +
    +
    +terminate_connection(endpoint, connection_app_home, connection_run_home)[source]¶
    +
    + +
    +
    +valid_connection(guid)[source]¶
    +

    Check if the connection is available.

    + +++ + + + + + +
    Parameters:guid (int) – Guid of the current RM
    Return type:Boolean
    +
    + +
    +
    +verify_connection(remote_endpoint, connection_app_home, connection_run_home)[source]¶
    +
    + +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.util.html b/doc/sphinx/_build/html/_layout/nepi.util.html new file mode 100644 index 00000000..e888283b --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.util.html @@ -0,0 +1,1227 @@ + + + + + + + + nepi.util package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +

    nepi.util package¶

    + +
    +

    Submodules¶

    +
    +
    +

    nepi.util.environ module¶

    +
    +
    +nepi.util.environ.execute(cmd)[source]¶
    +
    + +
    +
    +nepi.util.environ.backticks(cmd)[source]¶
    +
    + +
    +
    +

    nepi.util.execfuncs module¶

    +
    +
    +nepi.util.execfuncs.lcopy(source, dest, recursive=False)[source]¶
    +

    Copies from/to localy.

    +
    + +
    +
    +nepi.util.execfuncs.lexec(command, user=None, sudo=False, env=None)[source]¶
    +

    Executes a local command, returns ((stdout,stderr),process)

    +
    + +
    +
    +nepi.util.execfuncs.lgetpid(pidfile)[source]¶
    +

    Check the pidfile of a process spawned with remote_spawn.

    +
    +
    Parameters:
    +
    pidfile: the pidfile passed to remote_span
    +
    +

    Returns:

    +
    +
    A (pid, ppid) tuple useful for calling remote_status and remote_kill, +or None if the pidfile isn’t valid yet (maybe the process is still starting).
    +
    + +
    +
    +nepi.util.execfuncs.lkill(pid, ppid, sudo=False)[source]¶
    +

    Kill a process spawned with lspawn.

    +

    First tries a SIGTERM, and if the process does not end in 10 seconds, +it sends a SIGKILL.

    +
    +
    Parameters:
    +

    pid/ppid: pid and parent-pid of the spawned process. See remote_check_pid

    +

    sudo: whether the command was run with sudo - careful killing like this.

    +
    +
    +

    Returns:

    +
    +
    Nothing, should have killed the process
    +
    + +
    +
    +nepi.util.execfuncs.lspawn(command, pidfile, stdout='/dev/null', stderr=<class nepi.util.sshfuncs.STDOUT at 0x7f028ff15bb0>, stdin='/dev/null', home=None, create_home=False, sudo=False, user=None)[source]¶
    +

    Spawn a local command such that it will continue working asynchronously.

    +
    +
    Parameters:
    +

    command: the command to run - it should be a single line.

    +

    pidfile: path of a (ideally unique to this task) pidfile for tracking the process.

    +
    +
    stdout: path of a file to redirect standard output to - must be a string.
    +
    Defaults to /dev/null
    +
    stderr: path of a file to redirect standard error to - string or the special STDOUT value
    +
    to redirect to the same file stdout was redirected to. Defaults to STDOUT.
    +
    +

    stdin: path of a file with input to be piped into the command’s standard input

    +

    home: path of a folder to use as working directory - should exist, unless you specify create_home

    +

    create_home: if True, the home folder will be created first with mkdir -p

    +

    sudo: whether the command needs to be executed as root

    +
    +
    Returns:
    +

    (stdout, stderr), process

    +

    Of the spawning process, which only captures errors at spawning time. +Usually only useful for diagnostics.

    +
    +
    +
    + +
    +
    +nepi.util.execfuncs.lstatus(pid, ppid)[source]¶
    +

    Check the status of a process spawned with remote_spawn.

    +
    +
    Parameters:
    +
    pid/ppid: pid and parent-pid of the spawned process. See remote_check_pid
    +
    +

    Returns:

    +
    +
    One of NOT_STARTED, RUNNING, FINISHED
    +
    + +
    +
    +

    nepi.util.guid module¶

    +
    +
    +class nepi.util.guid.GuidGenerator[source]¶
    +

    Bases: object

    +
    +
    +next(guid=None)[source]¶
    +
    + +
    + +
    +
    +

    nepi.util.logger module¶

    +
    +
    +class nepi.util.logger.Logger(logger_component)[source]¶
    +

    Bases: object

    +
    +
    +debug(msg, out=None, err=None)[source]¶
    +
    + +
    +
    +error(msg, out=None, err=None)[source]¶
    +
    + +
    +
    +info(msg, out=None, err=None)[source]¶
    +
    + +
    +
    +log(msg, level, out=None, err=None)[source]¶
    +
    + +
    +
    +log_message(msg)[source]¶
    +
    + +
    +
    +logger[source]¶
    +
    + +
    +
    +warning(msg, out=None, err=None)[source]¶
    +
    + +
    + +
    +
    +

    nepi.util.manifoldapi module¶

    +
    +
    +class nepi.util.manifoldapi.MANIFOLDAPI(username, password, hostname, urlpattern)[source]¶
    +

    Bases: object

    +

    API to query different data platforms as SFA, TopHat, OML Central Server, +using Manifold Framework, the backend of MySlice.

    +
    +
    +add_resource_to_slice(slicename, resource_urn)[source]¶
    +

    Add resource to user’s slice. The query needs to specify the new +resource plus the previous resources already in the slice.

    +
    + +
    +
    +api[source]¶
    +
    + +
    +
    +get_resource_info(filters=None, fields=None)[source]¶
    +

    Create and execute the Manifold API Query to get the resources +according fields and filters. +:param filters: resource’s constraints for the experiment +:type filters: dict +:param fields: desire fields in the result of the query +:type fields: list

    +
    + +
    +
    +get_resource_urn(filters=None)[source]¶
    +

    Retrieves the resources urn of the resources matching filters.

    +
    + +
    +
    +get_session_key()[source]¶
    +

    Retrieves the session key, in order to use the same session for +queries.

    +
    + +
    +
    +get_slice_resources(slicename)[source]¶
    +

    Retrieves resources attached to user’s slice. +return value: list of resources’ urn

    +
    + +
    +
    +remove_resource_from_slice(slicename, resource_urn)[source]¶
    +

    Remove resource from user’s slice. The query needs to specify the list +of previous resources in the slice without the one to be remove.

    +
    + +
    + +
    +
    +class nepi.util.manifoldapi.MANIFOLDAPIFactory[source]¶
    +

    Bases: object

    +

    API Factory to manage a map of MANIFOLDAPI instances as key-value pairs, it +instanciate a single instance per key. The key represents the same SFA, +MF (ManiFold) credentials.

    +
    +
    +classmethod get_api(username, password, hostname='test.myslice.info', urlpattern='http://%(hostname)s:7080')[source]¶
    +
    +++ + + + +
    Parameters:
      +
    • username (str) – Manifold user (also used for MySlice web login)
    • +
    • password (str) – Manifold password (also used for MySlice web login)
    • +
    • hostname (str) – Hostname of the Manifold API to query SFA, TopHat, etc
    • +
    • urlpattern (str) – Url of the Manifold API to query SFA, TopHat, etc
    • +
    +
    +
    + +
    +
    +classmethod make_key(*args)[source]¶
    +
    + +
    + +
    +
    +

    nepi.util.netgraph module¶

    +
    +
    +class nepi.util.netgraph.NetGraph(**kwargs)[source]¶
    +

    Bases: object

    +

    NetGraph represents a network topology. +Network graphs are internally using the networkx library.

    +
    +
    +add_edge(nid1, nid2)[source]¶
    +
    + +
    +
    +add_node(nid)[source]¶
    +
    + +
    +
    +annotate_edge(nid1, nid2, name, value)[source]¶
    +
    + +
    +
    +annotate_edge_net(nid1, nid2, ip1, ip2, mask, network, prefixlen)[source]¶
    +
    + +
    +
    +annotate_node(nid, name, value)[source]¶
    +
    + +
    +
    +annotate_node_ip(nid, ip)[source]¶
    +
    + +
    +
    +assign_p2p_ips(network='10.0.0.0', prefix=8, version=4)[source]¶
    +

    Assign IP addresses to each end of each edge of the network graph, +computing all the point to point subnets and addresses in the network +representation.

    +
    +
    +++ + + + + + + + + + + + + + +
    param network:Base network address used for subnetting.
    type network:str
    param prefix:Prefix for the base network address used for subnetting.
    type prefixt:int
    param version:IP version (either 4 or 6).
    type version:int
    +
    +
    + +
    +
    +del_edge_annotation(nid1, nid2, name)[source]¶
    +
    + +
    +
    +del_node_annotation(nid, name)[source]¶
    +
    + +
    +
    +edge_annotation(nid1, nid2, name)[source]¶
    +
    + +
    +
    +edge_annotations(nid1, nid2)[source]¶
    +
    + +
    +
    +edge_net_annotation(nid1, nid2)[source]¶
    +
    + +
    +
    +edges()[source]¶
    +
    + +
    +
    +generate_topology(topo_type, node_count, branches=None)[source]¶
    +
    + +
    +
    +get_p2p_info(nid1, nid2)[source]¶
    +
    + +
    +
    +is_source(nid)[source]¶
    +
    + +
    +
    +is_target(nid)[source]¶
    +
    + +
    +
    +node_annotation(nid, name)[source]¶
    +
    + +
    +
    +node_annotations(nid)[source]¶
    +
    + +
    +
    +node_ip_annotations(nid)[source]¶
    +
    + +
    +
    +nodes()[source]¶
    +
    + +
    +
    +order[source]¶
    +
    + +
    +
    +select_random_source(**kwargs)[source]¶
    +

    Mark a random node as source.

    +
    + +
    +
    +select_target_zero()[source]¶
    +

    Mark the node 0 as target

    +
    + +
    +
    +set_source(nid)[source]¶
    +
    + +
    +
    +set_target(nid)[source]¶
    +
    + +
    +
    +sources()[source]¶
    +

    Returns the nodes that are sources

    +
    + +
    +
    +targets()[source]¶
    +

    Returns the nodes that are targets

    +
    + +
    +
    +topo_type[source]¶
    +
    + +
    +
    +topology[source]¶
    +
    + +
    + +
    +
    +class nepi.util.netgraph.TopologyType[source]¶
    +
    +
    +ADHOC = 'adhoc'¶
    +
    + +
    +
    +LADDER = 'ladder'¶
    +
    + +
    +
    +LINEAR = 'linear'¶
    +
    + +
    +
    +MESH = 'mesh'¶
    +
    + +
    +
    +STAR = 'star'¶
    +
    + +
    +
    +TREE = 'tree'¶
    +
    + +
    + +
    +
    +

    nepi.util.parallel module¶

    +
    +
    +class nepi.util.parallel.ParallelRun(maxthreads=None, maxqueue=None, results=True)[source]¶
    +

    Bases: object

    +
    +
    +destroy()[source]¶
    +
    + +
    +
    +empty()[source]¶
    +
    + +
    +
    +initialize_workers()[source]¶
    +
    + +
    +
    +join()[source]¶
    +
    + +
    +
    +put(callable, *args, **kwargs)[source]¶
    +
    + +
    +
    +put_nowait(callable, *args, **kwargs)[source]¶
    +
    + +
    +
    +start()[source]¶
    +
    + +
    +
    +sync()[source]¶
    +
    + +
    + +
    +
    +class nepi.util.parallel.WorkerThread(group=None, target=None, name=None, args=(), kwargs=None, verbose=None)[source]¶
    +

    Bases: threading.Thread

    +
    +
    +class QUIT[source]¶
    +
    + +
    +
    +WorkerThread.attach(queue, rvqueue, delayed_exceptions)[source]¶
    +
    + +
    +
    +WorkerThread.quit()[source]¶
    +
    + +
    +
    +WorkerThread.run()[source]¶
    +
    + +
    + +
    +
    +

    nepi.util.plotter module¶

    +
    +
    +class nepi.util.plotter.ECPlotter[source]¶
    +

    Bases: object

    +
    +
    +plot(ec, dirpath=None, format='figure', show=False)[source]¶
    +
    + +
    + +
    +
    +class nepi.util.plotter.PFormats[source]¶
    +
    +
    +DOT = 'dot'¶
    +
    + +
    +
    +FIGURE = 'figure'¶
    +
    + +
    + +
    +
    +

    nepi.util.rmatcher module¶

    +
    +
    +nepi.util.rmatcher.find_boxes(box, all_tags=None, exact_tags=None, max_depth=1)[source]¶
    +

    Look for the connected boxes with the required tags, doing breath-first +search, until max_depth ( max_depth = None will traverse the entire graph ).

    +
    + +
    +
    +nepi.util.rmatcher.match_tags(box, all_tags, exact_tags)[source]¶
    +

    returns True if box has required tags

    +
    + +
    +
    +

    nepi.util.serializer module¶

    +
    +
    +class nepi.util.serializer.ECSerializer[source]¶
    +

    Bases: object

    +
    +
    +load(filepath, format='xml')[source]¶
    +
    + +
    +
    +save(ec, dirpath, format='xml')[source]¶
    +
    + +
    +
    +serialize(ec, format='xml')[source]¶
    +
    + +
    + +
    +
    +class nepi.util.serializer.SFormats[source]¶
    +
    +
    +XML = 'xml'¶
    +
    + +
    + +
    +
    +

    nepi.util.sfaapi module¶

    +
    +
    +class nepi.util.sfaapi.SFAAPI(sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, ec, batch, rtype, timeout)[source]¶
    +

    Bases: object

    +

    API for quering the SFA service. It uses Sfi class from the tool sfi client.

    +
    +
    +add_resource_to_slice(slicename, resource_hrn, leases=None)[source]¶
    +

    Get the list of resources’ urn, build the rspec string and call the allocate +and provision method.

    +
    + +
    +
    +add_resource_to_slice_batch(slicename, resource_hrn, properties=None, leases=None)[source]¶
    +

    Method to add all resources together to the slice. Previous deletion of slivers. +Specially used for wilabt that doesn’t allow to add more resources to the slice +after some resources are added. Every sliver have to be deleted and the batch +has to be added at once.

    +
    + +
    +
    +blacklist_resource(resource_hrn)[source]¶
    +

    Adding resource_hrn to blacklist, and taking +the resource from the reserved list.

    +
    + +
    +
    +blacklisted(resource_hrn)[source]¶
    +

    Check if the resource is in the blacklist.

    +
    + +
    +
    +get_resources_hrn(resources=None)[source]¶
    +

    Get list of resources hrn, without the resource info.

    +
    + +
    +
    +get_resources_info()[source]¶
    +

    Get all resources and its attributes from aggregate.

    +
    + +
    +
    +get_slice_resources(slicename)[source]¶
    +

    Get resources and info from slice.

    +
    + +
    +
    +release()[source]¶
    +

    Remove hosts from the reserved and blacklist lists, and in case +the persist attribute is set, it saves the blacklisted hosts +in the blacklist file.

    +
    + +
    +
    +remove_all_from_slice(slicename)[source]¶
    +

    De-allocate and de-provision all slivers of the named slice. +Currently sfi doesn’t support removing particular +slivers, so this method works only for removing every sliver. Setting the +resource_hrn parameter is not necessary.

    +
    + +
    +
    +remove_resource_from_slice(slicename, resource_hrn, leases=None)[source]¶
    +

    Remove slivers from slice. Currently sfi doesn’t support removing particular +slivers.

    +
    + +
    +
    +reserve_resource(resource_hrn)[source]¶
    +

    Add resource to the reserved list.

    +
    + +
    +
    +reserved(resource_hrn)[source]¶
    +

    Check that the resource in not reserved.

    +
    + +
    + +
    +
    +class nepi.util.sfaapi.SFAAPIFactory[source]¶
    +

    Bases: object

    +

    API Factory to manage a map of SFAAPI instances as key-value pairs, it +instanciate a single instance per key. The key represents the same SFA, +credentials.

    +
    +
    +classmethod get_api(sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, ec, batch=False, rtype=None, timeout=None)[source]¶
    +
    + +
    +
    +classmethod make_key(*args)[source]¶
    +
    + +
    + +
    +
    +

    nepi.util.sfarspec_proc module¶

    +
    +
    +class nepi.util.sfarspec_proc.SfaRSpecProcessing(config=None)[source]¶
    +

    Bases: object

    +

    Class to process SFA RSpecs, parse the RSpec replies such as Advertisement RSpecs, +and build in the case of Request RSpecs.

    +
    +
    +build_sfa_rspec(slice_id, resources, properties, leases)[source]¶
    +

    Build the XML RSpec from list of resources’ urns. +eg. resources = [“urn:publicid:IDN+ple:modenaple+node+planetlab-1.ing.unimo.it“]

    +
    + +
    +
    +make_dict_rec(obj)[source]¶
    +
    + +
    +
    +parse_sfa_rspec(rspec_string)[source]¶
    +

    Parse the RSpec XML as a string.

    +
    + +
    + +
    +
    +

    nepi.util.sshfuncs module¶

    +
    +
    +class nepi.util.sshfuncs.ProcStatus[source]¶
    +

    Codes for status of remote spawned process

    +
    +
    +FINISHED = 2¶
    +
    + +
    +
    +NOT_STARTED = 3¶
    +
    + +
    +
    +RUNNING = 1¶
    +
    + +
    + +
    +
    +class nepi.util.sshfuncs.STDOUT[source]¶
    +

    Special value that when given to rspawn in stderr causes stderr to +redirect to whatever stdout was redirected to.

    +
    + +
    +
    +nepi.util.sshfuncs.eintr_retry(func)[source]¶
    +

    Retries a function invocation when a EINTR occurs

    +
    + +
    +
    +nepi.util.sshfuncs.gethostbyname(host)[source]¶
    +
    + +
    +
    +nepi.util.sshfuncs.log(msg, level, out=None, err=None)[source]¶
    +
    + +
    +
    +nepi.util.sshfuncs.make_control_path(agent, forward_x11)[source]¶
    +
    + +
    +
    +nepi.util.sshfuncs.make_server_key_args(server_key, host, port)[source]¶
    +

    Returns a reference to a temporary known_hosts file, to which +the server key has been added.

    +

    Make sure to hold onto the temp file reference until the process is +done with it

    + +++ + + + +
    Parameters:
      +
    • server_key (str) – the server public key
    • +
    • host (str) – the hostname
    • +
    • port (str) – the ssh port
    • +
    +
    +
    + +
    +
    +nepi.util.sshfuncs.openssh_has_persist()[source]¶
    +

    The ssh_config options ControlMaster and ControlPersist allow to +reuse a same network connection for multiple ssh sessions. In this +way limitations on number of open ssh connections can be bypassed. +However, older versions of openSSH do not support this feature. +This function is used to determine if ssh connection persist features +can be used.

    +
    + +
    +
    +nepi.util.sshfuncs.rcopy(source, dest, port=None, gwuser=None, gw=None, recursive=False, identity=None, server_key=None, retry=3, strict_host_checking=True)[source]¶
    +

    Copies from/to remote sites.

    +

    Source and destination should have the user and host encoded +as per scp specs.

    +

    Source can be a list of files to copy to a single destination, +(in which case it is advised that the destination be a folder), +or a single file in a string.

    +
    + +
    +
    +nepi.util.sshfuncs.resolve_hostname(host)[source]¶
    +
    + +
    +
    +nepi.util.sshfuncs.rexec(command, host, user, port=None, gwuser=None, gw=None, agent=True, sudo=False, identity=None, server_key=None, env=None, tty=False, connect_timeout=30, retry=3, persistent=True, forward_x11=False, blocking=True, strict_host_checking=True)[source]¶
    +

    Executes a remote command, returns ((stdout,stderr),process)

    +
    + +
    +
    +nepi.util.sshfuncs.rgetpid(*p, **kw)[source]¶
    +

    Returns the pid and ppid of a process from a remote file where the +information was stored.

    +
    +
    +++ + + + + + + + + + + + +
    param home:Path to directory where the pidfile is located
    type home:str
    param pidfile:Name of file containing the pid information
    type pidfile:str
    rtype:int
    +

    A (pid, ppid) tuple useful for calling rstatus and rkill, +or None if the pidfile isn’t valid yet (can happen when process is staring up)

    +
    +
    + +
    +
    +nepi.util.sshfuncs.rkill(*p, **kw)[source]¶
    +

    Sends a kill signal to a remote process.

    +

    First tries a SIGTERM, and if the process does not end in 10 seconds, +it sends a SIGKILL.

    +
    +
    +++ + + + + + + + + + + + + + +
    param pid:Process id of process to be killed
    type pid:int
    param ppid:Parent process id of process to be killed
    type ppid:int
    param sudo:Flag indicating if sudo should be used to kill the process
    type sudo:bool
    +
    +
    + +
    +
    +nepi.util.sshfuncs.rspawn(command, pidfile, stdout='/dev/null', stderr=<class nepi.util.sshfuncs.STDOUT at 0x7f028ff15bb0>, stdin='/dev/null', home=None, create_home=False, sudo=False, host=None, port=None, user=None, gwuser=None, gw=None, agent=None, identity=None, server_key=None, tty=False, strict_host_checking=True)[source]¶
    +

    Spawn a remote command such that it will continue working asynchronously in +background.

    +
    +
    +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    param command:The command to run, it should be a single line.
    type command:str
    param pidfile:Path to a file where to store the pid and ppid of the +spawned process
    type pidfile:str
    param stdout:Path to file to redirect standard output. +The default value is /dev/null
    type stdout:str
    param stderr:Path to file to redirect standard error. +If the special STDOUT value is used, stderr will +be redirected to the same file as stdout
    type stderr:str
    param stdin:Path to a file with input to be piped into the command’s standard input
    type stdin:str
    param home:Path to working directory folder. +It is assumed to exist unless the create_home flag is set.
    type home:str
    param create_home:
     Flag to force creation of the home folder before +running the command
    type create_home:
     bool
    param sudo:Flag forcing execution with sudo user
    type sudo:bool
    rtype:tuple
    +

    (stdout, stderr), process

    +

    Of the spawning process, which only captures errors at spawning time. +Usually only useful for diagnostics.

    +
    +
    + +
    +
    +nepi.util.sshfuncs.rstatus(*p, **kw)[source]¶
    +

    Returns a code representing the the status of a remote process

    +
    +
    +++ + + + + + + + + + + + +
    param pid:Process id of the process
    type pid:int
    param ppid:Parent process id of process
    type ppid:int
    rtype:int (One of NOT_STARTED, RUNNING, FINISHED)
    +
    +
    + +
    +
    +nepi.util.sshfuncs.shell_escape(s)[source]¶
    +

    Escapes strings so that they are safe to use as command-line +arguments

    +
    + +
    +
    +

    nepi.util.statfuncs module¶

    +
    +
    +nepi.util.statfuncs.compute_mean(sample)[source]¶
    +
    + +
    +
    +

    nepi.util.timefuncs module¶

    +
    +
    +nepi.util.timefuncs.compute_delay_ms(timestamp2, timestamp1)[source]¶
    +
    + +
    +
    +nepi.util.timefuncs.stabsformat(sdate, dbase=None)[source]¶
    +

    Constructs a datetime object from a string date. +The string date can be expressed as an absolute date +( i.e. format YYYYMMddHHMMSSffff ) or as a relative time +( e.g. format ‘5m’ or ‘10s’). +If the date is a relative time and the dbase parameter +is given (dbase must be datetime object), the returned +date will be dbase + sdate. If dbase is None, +current time will be used instead as base time.

    +

    :param date : string date +:type date : date

    +
    + +
    +
    +nepi.util.timefuncs.stformat(sdate)[source]¶
    +

    Constructs a datetime object from a string date with +format YYYYMMddHHMMSSffff

    +
    + +
    +
    +nepi.util.timefuncs.tdiff(date1, date2)[source]¶
    +

    Returns difference ( date1 - date2 ) as a datetime object, +where date1 and date 2 are datetime objects

    +
    + +
    +
    +nepi.util.timefuncs.tdiffsec(date1, date2)[source]¶
    +

    Returns the date difference ( date1 - date2 ) in seconds, +where date1 and date 2 are datetime objects

    +
    + +
    +
    +nepi.util.timefuncs.tnow()[source]¶
    +

    Returns datetime object with the current time

    +
    + +
    +
    +nepi.util.timefuncs.tsformat(date=None)[source]¶
    +

    Formats a datetime object to a string with format YYYYMMddHHMMSSffff. +If no date is given, the current date is used.

    +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.util.parsers.html b/doc/sphinx/_build/html/_layout/nepi.util.parsers.html new file mode 100644 index 00000000..c31a65de --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.util.parsers.html @@ -0,0 +1,151 @@ + + + + + + + + nepi.util.parsers package — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + +
    +
    +
    +
    + +
    +

    nepi.util.parsers package¶

    +
    +

    Submodules¶

    +
    +
    +

    nepi.util.parsers.xml_parser module¶

    +
    +
    +class nepi.util.parsers.xml_parser.ECXMLParser[source]¶
    +

    Bases: object

    +
    +
    +from_xml(xml)[source]¶
    +
    + +
    +
    +to_xml(ec)[source]¶
    +
    + +
    + +
    +
    +nepi.util.parsers.xml_parser.from_type(value)[source]¶
    +
    + +
    +
    +nepi.util.parsers.xml_parser.to_type(type, value)[source]¶
    +
    + +
    +
    +nepi.util.parsers.xml_parser.xmldecode(s, cast=<type 'str'>)[source]¶
    +
    + +
    +
    +nepi.util.parsers.xml_parser.xmlencode(s)[source]¶
    +
    + +
    +
    +

    Module contents¶

    +
    +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/index.html b/doc/sphinx/_build/html/_modules/index.html new file mode 100644 index 00000000..976b752e --- /dev/null +++ b/doc/sphinx/_build/html/_modules/index.html @@ -0,0 +1,330 @@ + + + + + + + + Overview: module code — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    All modules for which code is available

    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/data/processing/ccn/parser.html b/doc/sphinx/_build/html/_modules/nepi/data/processing/ccn/parser.html new file mode 100644 index 00000000..57ea0d14 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/data/processing/ccn/parser.html @@ -0,0 +1,505 @@ + + + + + + + + nepi.data.processing.ccn.parser — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.data.processing.ccn.parser

    +#!/usr/bin/env python
    +
    +###############################################################################
    +#
    +#    CCNX benchmark
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#
    +###############################################################################
    +
    +#
    +# This library contains functions to parse (CCNx) ccnd logs.
    +#
    +# Results from experiments must be stored in a directory
    +# named with the experiment run id.
    +# ccnd logs are stored in .log files in a subdirectory per node.
    +# The following diagram exemplifies the experiment result directory
    +# structure (nidi is the unique identifier assigned to node i):
    +#
    +#    run_id
    +#               \   nid1
    +#                        \ nid2.log
    +#               \   nid2
    +#                        \ nid1.log
    +#               \   nid3
    +#                        \ nid3.log
    +#
    +
    +import collections
    +import functools
    +import networkx
    +import os
    +import pickle
    +import tempfile
    +
    +from nepi.util.timefuncs import compute_delay_ms
    +from nepi.util.statfuncs import compute_mean
    +import nepi.data.processing.ping.parser as ping_parser
    +
    +
    [docs]def is_control(content_name): + return content_name.startswith("ccnx:/%C1") or \ + content_name.startswith("ccnx:/ccnx") or \ + content_name.startswith("ccnx:/...") + +
    +
    [docs]def parse_file(filename): + """ Parses message information from ccnd log files + + filename: path to ccndlog file + + """ + + faces = dict() + sep = " " + + f = open(filename, "r") + + data = [] + + for line in f: + cols = line.strip().split(sep) + + # CCN_PEEK + # MESSAGE interest_from + # 1374181938.808523 ccnd[9245]: debug.4352 interest_from 6 ccnx:/test/bunny.ts (23 bytes,sim=0CDCC1D7) + # + # MESSAGE interest_to + # 1374181938.812750 ccnd[9245]: debug.3502 interest_to 5 ccnx:/test/bunny.ts (39 bytes,i=2844,sim=0CDCC1D7) + # + # MESSAGE CONTENT FROM + # 1374181938.868682 ccnd[9245]: debug.4643 content_from 5 ccnx:/test/bunny.ts/%FD%05%1E%85%8FVw/%00/%9E%3D%01%D9%3Cn%95%2BvZ%8 + # + # MESSAGE CONTENT_TO + # 1374181938.868772 ccnd[9245]: debug.1619 content_to 6 ccnx:/test/bunny.ts/%FD%05%1E%85%8FVw/%00/%9E%3D%01%D9%3Cn%95%2BvZ%8 + # + # 1375596708.222304 ccnd[9758]: debug.3692 interest_expiry ccnx:/test/bunny.ts/%FD%05%1E%86%B1GS/%00%0A%F7 (44 bytes,c=0:1,i=2819,sim=49FA8048) + + # External face creation + # 1374181452.965961 ccnd[9245]: accepted datagram client id=5 (flags=0x40012) 204.85.191.10 port 9695 + + if line.find("accepted datagram client") > -1: + face_id = (cols[5]).replace("id=",'') + ip = cols[7] + port = cols[9] + faces[face_id] = (ip, port) + continue + + # 1374181452.985296 ccnd[9245]: releasing face id 4 (slot 4) + if line.find("releasing face id") > -1: + face_id = cols[5] + if face_id in faces: + del faces[face_id] + continue + + if len(cols) < 6: + continue + + timestamp = cols[0] + message_type = cols[3] + + if message_type not in ["interest_from", "interest_to", "content_from", + "content_to", "interest_dupnonce", "interest_expiry"]: + continue + + face_id = cols[4] + content_name = cols[5] + + # Interest Nonce ? -> 412A74-0844-0008-50AA-F6EAD4 + nonce = "" + if message_type in ["interest_from", "interest_to", "interest_dupnonce"]: + last = cols[-1] + if len(last.split("-")) == 5: + nonce = last + + try: + size = int((cols[6]).replace('(','')) + except: + print "interest_expiry without face id!", line + continue + + # If no external IP address was identified for this face + # asume it is a local face + peer = "localhost" + + if face_id in faces: + peer, port = faces[face_id] + + data.append((content_name, timestamp, message_type, peer, face_id, + size, nonce, line)) + + f.close() + + return data +
    +
    [docs]def dump_content_history(content_history): + f = tempfile.NamedTemporaryFile(delete=False) + pickle.dump(content_history, f) + f.close() + return f.name +
    +
    [docs]def load_content_history(fname): + f = open(fname, "r") + content_history = pickle.load(f) + f.close() + + os.remove(fname) + return content_history +
    +
    [docs]def annotate_cn_node(graph, nid, ips2nid, data, content_history): + for (content_name, timestamp, message_type, peer, face_id, + size, nonce, line) in data: + + # Ignore control messages for the time being + if is_control(content_name): + continue + + if message_type == "interest_from" and \ + peer == "localhost": + graph.node[nid]["ccn_consumer"] = True + elif message_type == "content_from" and \ + peer == "localhost": + graph.node[nid]["ccn_producer"] = True + + # Ignore local messages for the time being. + # They could later be used to calculate the processing times + # of messages. + if peer == "localhost": + continue + + # remove digest + if message_type in ["content_from", "content_to"]: + content_name = "/".join(content_name.split("/")[:-1]) + + if content_name not in content_history: + content_history[content_name] = list() + + peernid = ips2nid[peer] + graph.add_edge(nid, peernid) + + content_history[content_name].append((timestamp, message_type, nid, + peernid, nonce, size, line)) +
    +
    [docs]def annotate_cn_graph(logs_dir, graph, parse_ping_logs = False): + """ Adds CCN content history for each node in the topology graph. + + """ + + # Make a copy of the graph to ensure integrity + graph = graph.copy() + + ips2nid = dict() + + for nid in graph.nodes(): + ips = graph.node[nid]["ips"] + for ip in ips: + ips2nid[ip] = nid + + found_files = False + + # Now walk through the ccnd logs... + for dirpath, dnames, fnames in os.walk(logs_dir): + # continue if we are not at the leaf level (if there are subdirectories) + if dnames: + continue + + # Each dirpath correspond to a different node + nid = os.path.basename(dirpath) + + # Cast to numeric nid if necessary + if int(nid) in graph.nodes(): + nid = int(nid) + + content_history = dict() + + for fname in fnames: + if fname.endswith(".log"): + found_files = True + filename = os.path.join(dirpath, fname) + data = parse_file(filename) + annotate_cn_node(graph, nid, ips2nid, data, content_history) + + # Avoid storing everything in memory, instead dump to a file + # and reference the file + fname = dump_content_history(content_history) + graph.node[nid]["history"] = fname + + if not found_files: + msg = "No CCND output files were found to parse at %s " % logs_dir + raise RuntimeError, msg + + if parse_ping_logs: + ping_parser.annotate_cn_graph(logs_dir, graph) + + return graph +
    +
    [docs]def ccn_producers(graph): + """ Returns the nodes that are content providers """ + return [nid for nid in graph.nodes() \ + if graph.node[nid].get("ccn_producer")] +
    +
    [docs]def ccn_consumers(graph): + """ Returns the nodes that are content consumers """ + return [nid for nid in graph.nodes() \ + if graph.node[nid].get("ccn_consumer")] +
    +
    [docs]def process_content_history(graph): + """ Compute CCN message counts and aggregates content historical + information in the content_names dictionary + + """ + + ## Assume single source + source = ccn_consumers(graph)[0] + + interest_expiry_count = 0 + interest_dupnonce_count = 0 + interest_count = 0 + content_count = 0 + content_names = dict() + + # Collect information about exchanged messages by content name and + # link delay info. + for nid in graph.nodes(): + # Load the data collected from the node's ccnd log + fname = graph.node[nid]["history"] + history = load_content_history(fname) + + for content_name in history.keys(): + hist = history[content_name] + + for (timestamp, message_type, nid1, nid2, nonce, size, line) in hist: + if message_type in ["content_from", "content_to"]: + # The first Interest sent will not have a version or chunk number. + # The first Content sent back in reply, will end in /=00 or /%00. + # Make sure to map the first Content to the first Interest. + if content_name.endswith("/=00"): + content_name = "/".join(content_name.split("/")[0:-2]) + + # Add content name to dictionary + if content_name not in content_names: + content_names[content_name] = dict() + content_names[content_name]["interest"] = dict() + content_names[content_name]["content"] = list() + + # Classify interests by replica + if message_type in ["interest_from"] and \ + nonce not in content_names[content_name]["interest"]: + content_names[content_name]["interest"][nonce] = list() + + # Add consumer history + if nid == source: + if message_type in ["interest_to", "content_from"]: + # content name history as seen by the source + if "consumer_history" not in content_names[content_name]: + content_names[content_name]["consumer_history"] = list() + + content_names[content_name]["consumer_history"].append( + (timestamp, message_type)) + + # Add messages per content name and cumulate totals by message type + if message_type == "interest_dupnonce": + interest_dupnonce_count += 1 + elif message_type == "interest_expiry": + interest_expiry_count += 1 + elif message_type == "interest_from": + interest_count += 1 + # Append to interest history of the content name + content_names[content_name]["interest"][nonce].append( + (timestamp, nid2, nid1)) + elif message_type == "content_from": + content_count += 1 + # Append to content history of the content name + content_names[content_name]["content"].append((timestamp, nid2, nid1)) + else: + continue + del hist + del history + + # Compute the time elapsed between the time an interest is sent + # in the consumer node and when the content is received back + for content_name in content_names.keys(): + # order content and interest messages by timestamp + content_names[content_name]["content"] = sorted( + content_names[content_name]["content"]) + + for nonce, timestamps in content_names[content_name][ + "interest"].iteritems(): + content_names[content_name]["interest"][nonce] = sorted( + timestamps) + + history = sorted(content_names[content_name]["consumer_history"]) + content_names[content_name]["consumer_history"] = history + + # compute the rtt time of the message + rtt = None + waiting_content = False + interest_timestamp = None + content_timestamp = None + + for (timestamp, message_type) in history: + if not waiting_content and message_type == "interest_to": + waiting_content = True + interest_timestamp = timestamp + continue + + if waiting_content and message_type == "content_from": + content_timestamp = timestamp + break + + # If we can't determine who sent the interest, discard it + rtt = -1 + if interest_timestamp and content_timestamp: + rtt = compute_delay_ms(content_timestamp, interest_timestamp) + + content_names[content_name]["rtt"] = rtt + content_names[content_name]["lapse"] = (interest_timestamp, content_timestamp) + + return (graph, + content_names, + interest_expiry_count, + interest_dupnonce_count, + interest_count, + content_count) +
    +
    [docs]def process_content_history_logs(logs_dir, graph, parse_ping_logs = False): + """ Parse CCN logs and aggregate content history information in graph. + Returns annotated graph and message countn and content names history. + + """ + ## Process logs and analyse data + try: + graph = annotate_cn_graph(logs_dir, graph, + parse_ping_logs = parse_ping_logs) + except: + print "Skipping: Error parsing ccnd logs", logs_dir + raise + + source = ccn_consumers(graph)[0] + target = ccn_producers(graph)[0] + + # Process the data from the ccnd logs, but do not re compute + # the link delay. + try: + (graph, + content_names, + interest_expiry_count, + interest_dupnonce_count, + interest_count, + content_count) = process_content_history(graph) + except: + print "Skipping: Error processing ccn data", logs_dir + raise + + return (graph, + content_names, + interest_expiry_count, + interest_dupnonce_count, + interest_count, + content_count)
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/data/processing/ping/parser.html b/doc/sphinx/_build/html/_modules/nepi/data/processing/ping/parser.html new file mode 100644 index 00000000..e69772ad --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/data/processing/ping/parser.html @@ -0,0 +1,212 @@ + + + + + + + + nepi.data.processing.ping.parser — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.data.processing.ping.parser

    +#!/usr/bin/env python
    +
    +###############################################################################
    +#
    +#    CCNX benchmark
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#
    +###############################################################################
    +
    +#
    +# This library contains functions to parse log files generated using ping. 
    +#
    +
    +import collections
    +import re
    +import os
    +
    +# RE to match line starting "traceroute to"
    +_rre = re.compile("\d+ bytes from ((?P<hostname>[^\s]+) )?\(?(?P<ip>[^\s]+)\)??: icmp_.eq=\d+ ttl=\d+ time=(?P<time>[^\s]+) ms")
    +
    +
    [docs]def parse_file(filename): + """ + filename: path to traceroute file + + """ + + f = open(filename, "r") + + # Traceroute info + target_ip = None + target_hostname = None + + data = [] + + for line in f: + # match traceroute to ... + m = re.match(_rre, line) + if not m: + continue + + target_ip = m.groupdict()["ip"] + # FIX THIS: Make sure the regular expression does not inlcude + # the ')' in the ip group + target_ip = target_ip.replace(")","") + target_hostname = m.groupdict()["hostname"] + time = m.groupdict()["time"] + data.append((target_ip, target_hostname, time)) + + f.close() + + return data +
    +
    [docs]def annotate_cn_node(graph, nid1, ips2nid, data): + for (target_ip, target_hostname, time) in data: + nid2 = ips2nid[target_ip] + + if "delays" not in graph.edge[nid1][nid2]: + graph.edge[nid1][nid2]["delays"] = [] + + time = float(time.replace("ms", "").replace(" ","")) + + graph.edge[nid1][nid2]["delays"].append(time) +
    +
    [docs]def annotate_cn_graph(logs_dir, graph): + """ Add delay inormation to graph using data collected using + ping. + + """ + ips2nid = dict() + + for nid in graph.nodes(): + ips = graph.node[nid]["ips"] + for ip in ips: + ips2nid[ip] = nid + + # Walk through the ping logs... + found_files = False + + for dirpath, dnames, fnames in os.walk(logs_dir): + # continue if we are not at the leaf level (if there are subdirectories) + if dnames: + continue + + # Each dirpath correspond to a different host + nid = os.path.basename(dirpath) + + for fname in fnames: + if fname.endswith(".ping"): + found_files = True + filename = os.path.join(dirpath, fname) + data = parse_file(filename) + annotate_cn_node(graph, nid, ips2nid, data) + + if not found_files: + msg = "No PING output files were found to parse at %s " % logs_dir + raise RuntimeError, msg + + # Take as weight the most frequent value + for nid1, nid2 in graph.edges(): + delays = collections.Counter(graph.edge[nid1][nid2]["delays"]) + weight = delays.most_common(1)[0][0] + del graph.edge[nid1][nid2]["delays"] + graph.edge[nid1][nid2]["weight"] = weight + + return graph +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/execution/attribute.html b/doc/sphinx/_build/html/_modules/nepi/execution/attribute.html new file mode 100644 index 00000000..8c87b68b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/execution/attribute.html @@ -0,0 +1,286 @@ + + + + + + + + nepi.execution.attribute — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.execution.attribute

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +### Attribute Types
    +
    [docs]class Types: + """ Allowed types for the Attribute value + """ + String = "STRING" + Bool = "BOOL" + Enumerate = "ENUM" + Double = "DOUBLE" + Integer = "INTEGER" + +### Attribute Flags
    +
    [docs]class Flags: + """ Flags to characterize the scope of an Attribute + """ + # Attribute value can not be read (it is hidden to the user) + NoRead = 1 # 1 + + # Attribute value can not be modified (it is not editable by the user) + NoWrite = 1 << 1 # 2 + + # Attribute value can be modified only before deployment + Design = 1 << 2 # 4 + + # Attribute value will be used at deployment time for initial configuration + Construct = 1 << 3 # 8 + + # Attribute provides credentials to access resources + Credential = 1 << 4 | Design # 16 + 4 + + # Attribute is a filter used to discover resources + Filter = 1 << 5 | Design # 32 + 4 + + # Attribute Flag is reserved for internal RM usage (i.e. should be + # transparent to the user) + Reserved = 1 << 6 # 64 + + # Attribute global is set to all resources of rtype + Global = 1 << 7 # 128 + +
    +
    [docs]class Attribute(object): + """ An Attribute exposes a configuration parameter of a resource + """ + + def __init__(self, name, help, type = Types.String, + flags = None, default = None, allowed = None, + range = None, set_hook = None): + """ + :param name: Name of the Attribute + :type name: str + + :param help: Description of the Attribute + :type help: str + + :param type: The type expected for the Attribute value. + Should be one of Attribute.Types + :type type: str + + :param flags: Defines Attribute behavior (i.e. whether it is read-only, + read and write, etc). This parameter must take its values from + Attribute.Flags. Flags values can be bitwised + :type flags: hex + + :param default: Default value for the Attribute + :type default: Depends on the type of Attribute + + :param allowed: List of values that the Attribute can take. + This parameter is only meaningful for Enumerate type Attributes + :type allowed: list + + :param range: (max, min) tuple with range of possible values for + Attributes. + This parameter is only meaningful for Integer or Double type + Attributes + :type range: (int, int) or (float, float) + + :param set_hook: Function that will be executed whenever a new + value is set for the Attribute. + :type set_hook: function + + """ + self._name = name + self._help = help + self._type = type + self._flags = flags or 0 + self._allowed = allowed + self._range = range + self._default = self._value = default + # callback to be invoked upon changing the + # attribute value + self.set_hook = set_hook + + @property +
    [docs] def name(self): + """ Returns the name of the Attribute """ + return self._name +
    + @property +
    [docs] def default(self): + """ Returns the default value of the Attribute """ + return self._default +
    + @property +
    [docs] def type(self): + """ Returns the type of the Attribute """ + return self._type +
    + @property +
    [docs] def help(self): + """ Returns the description of the Attribute """ + return self._help +
    + @property +
    [docs] def flags(self): + """ Returns the flags of the Attribute """ + return self._flags +
    + @property +
    [docs] def allowed(self): + """ Returns the set of allowed values for the Attribute """ + return self._allowed +
    + @property +
    [docs] def range(self): + """ Returns the range of allowed numerical values for the Attribute """ + return self._range +
    +
    [docs] def has_flag(self, flag): + """ Returns True if the Attribute has the flag 'flag' + + :param flag: Flag to be checked + :type flag: Flags + """ + return (self._flags & flag) == flag +
    +
    [docs] def get_value(self): + """ Returns the value of the Attribute """ + return self._value +
    +
    [docs] def set_value(self, value): + """ Configure a new value for the Attribute """ + valid = True + + if self.type == Types.Enumerate: + valid = value in self._allowed + + if self.type in [Types.Double, Types.Integer] and self.range: + (min, max) = self.range + + value = float(value) + + valid = (value >= min and value <= max) + + valid = valid and self.is_valid_value(value) + + if valid: + if self.set_hook: + # Hook receives old value, new value + value = self.set_hook(self._value, value) + + self._value = value + else: + raise ValueError("Invalid value %s for attribute %s" % + (str(value), self.name)) +
    + value = property(get_value, set_value) + +
    [docs] def is_valid_value(self, value): + """ Attribute subclasses will override this method to add + adequate validation""" + return True +
    + @property +
    [docs] def has_changed(self): + """ Returns True if the value has changed from the default """ + return self.value != self.default +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/execution/ec.html b/doc/sphinx/_build/html/_modules/nepi/execution/ec.html new file mode 100644 index 00000000..e95bbc47 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/execution/ec.html @@ -0,0 +1,1365 @@ + + + + + + + + nepi.execution.ec — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.execution.ec

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.util import guid
    +from nepi.util.parallel import ParallelRun
    +from nepi.util.timefuncs import tnow, tdiffsec, stabsformat, tsformat 
    +from nepi.execution.resource import ResourceFactory, ResourceAction, \
    +        ResourceState, ResourceState2str
    +from nepi.execution.scheduler import HeapScheduler, Task, TaskStatus
    +from nepi.execution.trace import TraceAttr
    +from nepi.util.serializer import ECSerializer, SFormats
    +from nepi.util.plotter import ECPlotter, PFormats
    +from nepi.util.netgraph import NetGraph, TopologyType 
    +
    +# TODO: use multiprocessing instead of threading
    +# TODO: Allow to reconnect to a running experiment instance! (reconnect mode vs deploy mode)
    +
    +import functools
    +import logging
    +import os
    +import sys
    +import tempfile
    +import time
    +import threading
    +import weakref
    +
    +
    [docs]class FailureLevel(object): + """ Possible failure states for the experiment """ + OK = 1 + RM_FAILURE = 2 + EC_FAILURE = 3 +
    +
    [docs]class FailureManager(object): + """ The FailureManager is responsible for handling errors + and deciding whether an experiment should be aborted or not + """ + + def __init__(self): + self._ec = None + self._failure_level = FailureLevel.OK + self._abort = False + +
    [docs] def set_ec(self, ec): + self._ec = weakref.ref(ec) +
    + @property +
    [docs] def ec(self): + """ Returns the ExperimentController associated to this FailureManager + """ + return self._ec() +
    + @property +
    [docs] def abort(self): + return self._abort +
    +
    [docs] def eval_failure(self, guid): + """ Implements failure policy and sets the abort state of the + experiment based on the failure state and criticality of + the RM + + :param guid: Guid of the RM upon which the failure of the experiment + is evaluated + :type guid: int + + """ + if self._failure_level == FailureLevel.OK: + rm = self.ec.get_resource(guid) + state = rm.state + critical = rm.get("critical") + + if state == ResourceState.FAILED and critical: + self._failure_level = FailureLevel.RM_FAILURE + self._abort = True + self.ec.logger.debug("RM critical failure occurred on guid %d." \ + " Setting EC FAILURE LEVEL to RM_FAILURE" % guid) +
    +
    [docs] def set_ec_failure(self): + self._failure_level = FailureLevel.EC_FAILURE +
    +
    [docs]class ECState(object): + """ Possible states of the ExperimentController + + """ + RUNNING = 1 + FAILED = 2 + RELEASED = 3 + TERMINATED = 4 +
    +
    [docs]class ExperimentController(object): + """ + .. note:: + + An experiment, or scenario, is defined by a concrete set of resources, + and the behavior, configuration and interconnection of those resources. + The Experiment Description (ED) is a detailed representation of a + single experiment. It contains all the necessary information to + allow repeating the experiment. NEPI allows to describe + experiments by registering components (resources), configuring them + and interconnecting them. + + A same experiment (scenario) can be executed many times, generating + different results. We call an experiment execution (instance) a 'run'. + + The ExperimentController (EC), is the entity responsible of + managing an experiment run. The same scenario can be + recreated (and re-run) by instantiating an EC and recreating + the same experiment description. + + An experiment is represented as a graph of interconnected + resources. A resource is a generic concept in the sense that any + component taking part of an experiment, whether physical of + virtual, is considered a resource. A resources could be a host, + a virtual machine, an application, a simulator, a IP address. + + A ResourceManager (RM), is the entity responsible for managing a + single resource. ResourceManagers are specific to a resource + type (i.e. An RM to control a Linux application will not be + the same as the RM used to control a ns-3 simulation). + To support a new type of resource, a new RM must be implemented. + NEPI already provides a variety of RMs to control basic resources, + and new can be extended from the existing ones. + + Through the EC interface the user can create ResourceManagers (RMs), + configure them and interconnect them, to describe an experiment. + Describing an experiment through the EC does not run the experiment. + Only when the 'deploy()' method is invoked on the EC, the EC will take + actions to transform the 'described' experiment into a 'running' experiment. + + While the experiment is running, it is possible to continue to + create/configure/connect RMs, and to deploy them to involve new + resources in the experiment (this is known as 'interactive' deployment). + + An experiments in NEPI is identified by a string id, + which is either given by the user, or automatically generated by NEPI. + The purpose of this identifier is to separate files and results that + belong to different experiment scenarios. + However, since a same 'experiment' can be run many times, the experiment + id is not enough to identify an experiment instance (run). + For this reason, the ExperimentController has two identifier, the + exp_id, which can be re-used in different ExperimentController, + and the run_id, which is unique to one ExperimentController instance, and + is automatically generated by NEPI. + + """ + + @classmethod +
    [docs] def load(cls, filepath, format = SFormats.XML): + serializer = ECSerializer() + ec = serializer.load(filepath) + return ec +
    + def __init__(self, exp_id = None, local_dir = None, persist = False, + fm = None, add_node_callback = None, add_edge_callback = None, + **kwargs): + """ ExperimentController entity to model an execute a network + experiment. + + :param exp_id: Human readable name to identify the experiment + :type exp_id: str + + :param local_dir: Path to local directory where to store experiment + related files + :type local_dir: str + + :param persist: Save an XML description of the experiment after + completion at local_dir + :type persist: bool + + :param fm: FailureManager object. If None is given, the default + FailureManager class will be used + :type fm: FailureManager + + :param add_node_callback: Callback to invoke for node instantiation + when automatic topology creation mode is used + :type add_node_callback: function + + :param add_edge_callback: Callback to invoke for edge instantiation + when automatic topology creation mode is used + :type add_edge_callback: function + + """ + super(ExperimentController, self).__init__() + + # Logging + self._logger = logging.getLogger("ExperimentController") + + # Run identifier. It identifies a concrete execution instance (run) + # of an experiment. + # Since a same experiment (same configuration) can be executed many + # times, this run_id permits to separate result files generated on + # different experiment executions + self._run_id = tsformat() + + # Experiment identifier. Usually assigned by the user + # Identifies the experiment scenario (i.e. configuration, + # resources used, etc) + self._exp_id = exp_id or "exp-%s" % os.urandom(8).encode('hex') + + # Local path where to store experiment related files (results, etc) + if not local_dir: + local_dir = tempfile.gettempdir() # /tmp + + self._local_dir = local_dir + self._exp_dir = os.path.join(local_dir, self.exp_id) + self._run_dir = os.path.join(self.exp_dir, self.run_id) + + # If True persist the experiment controller in XML format, after completion + self._persist = persist + + # generator of globally unique ids + self._guid_generator = guid.GuidGenerator() + + # Resource managers + self._resources = dict() + + # Scheduler. It a queue that holds tasks scheduled for + # execution, and yields the next task to be executed + # ordered by execution and arrival time + self._scheduler = HeapScheduler() + + # Tasks + self._tasks = dict() + + # RM groups (for deployment) + self._groups = dict() + + # generator of globally unique id for groups + self._group_id_generator = guid.GuidGenerator() + + # Flag to stop processing thread + self._stop = False + + # Entity in charge of managing system failures + if not fm: + self._fm = FailureManager() + self._fm.set_ec(self) + + # EC state + self._state = ECState.RUNNING + + # Automatically construct experiment description + self._netgraph = None + if add_node_callback or add_edge_callback or kwargs.get("topology"): + self._build_from_netgraph(add_node_callback, add_edge_callback, + **kwargs) + + # The runner is a pool of threads used to parallelize + # execution of tasks + self._nthreads = 20 + self._runner = None + + # Event processing thread + self._cond = threading.Condition() + self._thread = threading.Thread(target = self._process) + self._thread.setDaemon(True) + self._thread.start() + + @property +
    [docs] def logger(self): + """ Returns the logger instance of the Experiment Controller + + """ + return self._logger +
    + @property +
    [docs] def fm(self): + """ Returns the failure manager + + """ + + return self._fm +
    + @property +
    [docs] def failure_level(self): + """ Returns the level of FAILURE of th experiment + + """ + + return self._fm._failure_level +
    + @property +
    [docs] def ecstate(self): + """ Returns the state of the Experiment Controller + + """ + return self._state +
    + @property +
    [docs] def exp_id(self): + """ Returns the experiment id assigned by the user + + """ + return self._exp_id +
    + @property +
    [docs] def run_id(self): + """ Returns the experiment instance (run) identifier (automatically + generated) + + """ + return self._run_id +
    + @property +
    [docs] def nthreads(self): + """ Returns the number of processing nthreads used + + """ + return self._nthreads +
    + @property +
    [docs] def local_dir(self): + """ Root local directory for experiment files + + """ + return self._local_dir +
    + @property +
    [docs] def exp_dir(self): + """ Local directory to store results and other files related to the + experiment. + + """ + return self._exp_dir +
    + @property +
    [docs] def run_dir(self): + """ Local directory to store results and other files related to the + experiment run. + + """ + return self._run_dir +
    + @property +
    [docs] def persist(self): + """ If True, persists the ExperimentController to XML format upon + experiment completion + + """ + return self._persist +
    + @property +
    [docs] def netgraph(self): + """ Return NetGraph instance if experiment description was automatically + generated + + """ + return self._netgraph +
    + @property +
    [docs] def abort(self): + """ Returns True if the experiment has failed and should be interrupted, + False otherwise. + + """ + return self._fm.abort +
    +
    [docs] def inform_failure(self, guid): + """ Reports a failure in a RM to the EC for evaluation + + :param guid: Resource id + :type guid: int + + """ + + return self._fm.eval_failure(guid) +
    +
    [docs] def wait_finished(self, guids): + """ Blocking method that waits until all RMs in the 'guids' list + have reached a state >= STOPPED (i.e. STOPPED, FAILED or + RELEASED ), or until a failure in the experiment occurs + (i.e. abort == True) + + :param guids: List of guids + :type guids: list + + """ + + def quit(): + return self.abort + + return self.wait(guids, state = ResourceState.STOPPED, + quit = quit) +
    +
    [docs] def wait_started(self, guids): + """ Blocking method that waits until all RMs in the 'guids' list + have reached a state >= STARTED, or until a failure in the + experiment occurs (i.e. abort == True) + + :param guids: List of guids + :type guids: list + + """ + + def quit(): + return self.abort + + return self.wait(guids, state = ResourceState.STARTED, + quit = quit) +
    +
    [docs] def wait_released(self, guids): + """ Blocking method that waits until all RMs in the 'guids' list + have reached a state == RELEASED, or until the EC fails + + :param guids: List of guids + :type guids: list + + """ + + def quit(): + return self._state == ECState.FAILED + + return self.wait(guids, state = ResourceState.RELEASED, + quit = quit) +
    +
    [docs] def wait_deployed(self, guids): + """ Blocking method that waits until all RMs in the 'guids' list + have reached a state >= READY, or until a failure in the + experiment occurs (i.e. abort == True) + + :param guids: List of guids + :type guids: list + + """ + + def quit(): + return self.abort + + return self.wait(guids, state = ResourceState.READY, + quit = quit) +
    +
    [docs] def wait(self, guids, state, quit): + """ Blocking method that waits until all RMs in the 'guids' list + have reached a state >= 'state', or until the 'quit' callback + yields True + + :param guids: List of guids + :type guids: list + + """ + if isinstance(guids, int): + guids = [guids] + + # Make a copy to avoid modifying the original guids list + guids = list(guids) + + while True: + # If there are no more guids to wait for + # or the quit function returns True, exit the loop + if len(guids) == 0 or quit(): + break + + # If a guid reached one of the target states, remove it from list + guid = guids.pop() + rm = self.get_resource(guid) + rstate = rm.state + + if rstate >= state: + self.logger.debug(" %s guid %d DONE - state is %s, required is >= %s " % ( + rm.get_rtype(), guid, rstate, state)) + else: + # Debug... + self.logger.debug(" WAITING FOR guid %d - state is %s, required is >= %s " % ( + guid, rstate, state)) + + guids.append(guid) + + time.sleep(0.5) +
    +
    [docs] def plot(self, dirpath = None, format= PFormats.FIGURE, show = False): + plotter = ECPlotter() + fpath = plotter.plot(self, dirpath = dirpath, format= format, + show = show) + return fpath +
    +
    [docs] def serialize(self, format = SFormats.XML): + serializer = ECSerializer() + sec = serializer.load(self, format = format) + return sec +
    +
    [docs] def save(self, dirpath = None, format = SFormats.XML): + if dirpath == None: + dirpath = self.run_dir + + try: + os.makedirs(dirpath) + except OSError: + pass + + serializer = ECSerializer() + path = serializer.save(self, dirpath, format = format) + return path +
    +
    [docs] def get_task(self, tid): + """ Returns a task by its id + + :param tid: Id of the task + :type tid: int + + :rtype: Task + + """ + return self._tasks.get(tid) +
    +
    [docs] def get_resource(self, guid): + """ Returns a registered ResourceManager by its guid + + :param guid: Id of the resource + :type guid: int + + :rtype: ResourceManager + + """ + rm = self._resources.get(guid) + return rm +
    +
    [docs] def get_resources_by_type(self, rtype): + """ Returns the ResourceManager objects of type rtype + + :param rtype: Resource type + :type rtype: string + + :rtype: list of ResourceManagers + + """ + rms = [] + for guid, rm in self._resources.iteritems(): + if rm.get_rtype() == rtype: + rms.append(rm) + return rms +
    +
    [docs] def remove_resource(self, guid): + del self._resources[guid] +
    + @property +
    [docs] def resources(self): + """ Returns the guids of all ResourceManagers + + :return: Set of all RM guids + :rtype: list + + """ + keys = self._resources.keys() + + return keys +
    +
    [docs] def filter_resources(self, rtype): + """ Returns the guids of all ResourceManagers of type rtype + + :param rtype: Resource type + :type rtype: string + + :rtype: list of guids + + """ + rms = [] + for guid, rm in self._resources.iteritems(): + if rm.get_rtype() == rtype: + rms.append(rm.guid) + return rms +
    +
    [docs] def register_resource(self, rtype, guid = None): + """ Registers a new ResourceManager of type 'rtype' in the experiment + + This method will assign a new 'guid' for the RM, if no guid + is specified. + + :param rtype: Type of the RM + :type rtype: str + + :return: Guid of the RM + :rtype: int + + """ + # Get next available guid + guid = self._guid_generator.next(guid) + + # Instantiate RM + rm = ResourceFactory.create(rtype, self, guid) + + # Store RM + self._resources[guid] = rm + + return guid +
    +
    [docs] def get_attributes(self, guid): + """ Returns all the attributes of the RM with guid 'guid' + + :param guid: Guid of the RM + :type guid: int + + :return: List of attributes + :rtype: list + + """ + rm = self.get_resource(guid) + return rm.get_attributes() +
    +
    [docs] def get_attribute(self, guid, name): + """ Returns the attribute 'name' of the RM with guid 'guid' + + :param guid: Guid of the RM + :type guid: int + + :param name: Name of the attribute + :type name: str + + :return: The attribute with name 'name' + :rtype: Attribute + + """ + rm = self.get_resource(guid) + return rm.get_attribute(name) +
    +
    [docs] def register_connection(self, guid1, guid2): + """ Registers a connection between a RM with guid 'guid1' + and another RM with guid 'guid2'. + + The order of the in which the two guids are provided is not + important, since the connection relationship is symmetric. + + :param guid1: First guid to connect + :type guid1: ResourceManager + + :param guid2: Second guid to connect + :type guid: ResourceManager + + """ + rm1 = self.get_resource(guid1) + rm2 = self.get_resource(guid2) + + rm1.register_connection(guid2) + rm2.register_connection(guid1) +
    +
    [docs] def register_condition(self, guids1, action, guids2, state, + time = None): + """ Registers an action START, STOP or DEPLOY for all RM on list + guids1 to occur at time 'time' after all elements in list guids2 + have reached state 'state'. + + :param guids1: List of guids of RMs subjected to action + :type guids1: list + + :param action: Action to perform (either START, STOP or DEPLOY) + :type action: ResourceAction + + :param guids2: List of guids of RMs to we waited for + :type guids2: list + + :param state: State to wait for on RMs of list guids2 (STARTED, + STOPPED, etc) + :type state: ResourceState + + :param time: Time to wait after guids2 has reached status + :type time: string + + """ + if isinstance(guids1, int): + guids1 = [guids1] + if isinstance(guids2, int): + guids2 = [guids2] + + for guid1 in guids1: + rm = self.get_resource(guid1) + rm.register_condition(action, guids2, state, time) +
    +
    [docs] def enable_trace(self, guid, name): + """ Enables a trace to be collected during the experiment run + + :param name: Name of the trace + :type name: str + + """ + rm = self.get_resource(guid) + rm.enable_trace(name) +
    +
    [docs] def trace_enabled(self, guid, name): + """ Returns True if the trace of name 'name' is enabled + + :param name: Name of the trace + :type name: str + + """ + rm = self.get_resource(guid) + return rm.trace_enabled(name) +
    +
    [docs] def trace(self, guid, name, attr = TraceAttr.ALL, block = 512, offset = 0): + """ Returns information on a collected trace, the trace stream or + blocks (chunks) of the trace stream + + :param name: Name of the trace + :type name: str + + :param attr: Can be one of: + - TraceAttr.ALL (complete trace content), + - TraceAttr.STREAM (block in bytes to read starting + at offset), + - TraceAttr.PATH (full path to the trace file), + - TraceAttr.SIZE (size of trace file). + :type attr: str + + :param block: Number of bytes to retrieve from trace, when attr is + TraceAttr.STREAM + :type name: int + + :param offset: Number of 'blocks' to skip, when attr is TraceAttr.STREAM + :type name: int + + :rtype: str + + """ + rm = self.get_resource(guid) + return rm.trace(name, attr, block, offset) +
    +
    [docs] def get_traces(self, guid): + """ Returns the list of the trace names of the RM with guid 'guid' + + :param guid: Guid of the RM + :type guid: int + + :return: List of trace names + :rtype: list + + """ + rm = self.get_resource(guid) + return rm.get_traces() + +
    +
    [docs] def discover(self, guid): + """ Discovers an available resource matching the criteria defined + by the RM with guid 'guid', and associates that resource to the RM + + Not all RM types require (or are capable of) performing resource + discovery. For the RM types which are not capable of doing so, + invoking this method does not have any consequences. + + :param guid: Guid of the RM + :type guid: int + + """ + rm = self.get_resource(guid) + return rm.discover() +
    +
    [docs] def provision(self, guid): + """ Provisions the resource associated to the RM with guid 'guid'. + + Provisioning means making a resource 'accessible' to the user. + Not all RM types require (or are capable of) performing resource + provisioning. For the RM types which are not capable of doing so, + invoking this method does not have any consequences. + + :param guid: Guid of the RM + :type guid: int + + """ + rm = self.get_resource(guid) + return rm.provision() +
    +
    [docs] def get(self, guid, name): + """ Returns the value of the attribute with name 'name' on the + RM with guid 'guid' + + :param guid: Guid of the RM + :type guid: int + + :param name: Name of the attribute + :type name: str + + :return: The value of the attribute with name 'name' + + """ + rm = self.get_resource(guid) + return rm.get(name) +
    +
    [docs] def set(self, guid, name, value): + """ Modifies the value of the attribute with name 'name' on the + RM with guid 'guid'. + + :param guid: Guid of the RM + :type guid: int + + :param name: Name of the attribute + :type name: str + + :param value: Value of the attribute + + """ + rm = self.get_resource(guid) + rm.set(name, value) +
    +
    [docs] def get_global(self, rtype, name): + """ Returns the value of the global attribute with name 'name' on the + RMs of rtype 'rtype'. + + :param guid: Guid of the RM + :type guid: int + + :param name: Name of the attribute + :type name: str + + :return: The value of the attribute with name 'name' + + """ + rclass = ResourceFactory.get_resource_type(rtype) + return rclass.get_global(name) +
    +
    [docs] def set_global(self, rtype, name, value): + """ Modifies the value of the global attribute with name 'name' on the + RMs of with rtype 'rtype'. + + :param guid: Guid of the RM + :type guid: int + + :param name: Name of the attribute + :type name: str + + :param value: Value of the attribute + + """ + rclass = ResourceFactory.get_resource_type(rtype) + return rclass.set_global(name, value) +
    +
    [docs] def state(self, guid, hr = False): + """ Returns the state of a resource + + :param guid: Resource guid + :type guid: integer + + :param hr: Human readable. Forces return of a + status string instead of a number + :type hr: boolean + + """ + rm = self.get_resource(guid) + state = rm.state + + if hr: + return ResourceState2str.get(state) + + return state +
    +
    [docs] def stop(self, guid): + """ Stops the RM with guid 'guid' + + Stopping a RM means that the resource it controls will + no longer take part of the experiment. + + :param guid: Guid of the RM + :type guid: int + + """ + rm = self.get_resource(guid) + return rm.stop() +
    +
    [docs] def start(self, guid): + """ Starts the RM with guid 'guid' + + Starting a RM means that the resource it controls will + begin taking part of the experiment. + + :param guid: Guid of the RM + :type guid: int + + """ + rm = self.get_resource(guid) + return rm.start() +
    +
    [docs] def get_start_time(self, guid): + """ Returns the start time of the RM as a timestamp """ + rm = self.get_resource(guid) + return rm.start_time +
    +
    [docs] def get_stop_time(self, guid): + """ Returns the stop time of the RM as a timestamp """ + rm = self.get_resource(guid) + return rm.stop_time +
    +
    [docs] def get_discover_time(self, guid): + """ Returns the discover time of the RM as a timestamp """ + rm = self.get_resource(guid) + return rm.discover_time +
    +
    [docs] def get_provision_time(self, guid): + """ Returns the provision time of the RM as a timestamp """ + rm = self.get_resource(guid) + return rm.provision_time +
    +
    [docs] def get_ready_time(self, guid): + """ Returns the deployment time of the RM as a timestamp """ + rm = self.get_resource(guid) + return rm.ready_time +
    +
    [docs] def get_release_time(self, guid): + """ Returns the release time of the RM as a timestamp """ + rm = self.get_resource(guid) + return rm.release_time +
    +
    [docs] def get_failed_time(self, guid): + """ Returns the time failure occured for the RM as a timestamp """ + rm = self.get_resource(guid) + return rm.failed_time +
    +
    [docs] def set_with_conditions(self, name, value, guids1, guids2, state, + time = None): + """ Modifies the value of attribute with name 'name' on all RMs + on the guids1 list when time 'time' has elapsed since all + elements in guids2 list have reached state 'state'. + + :param name: Name of attribute to set in RM + :type name: string + + :param value: Value of attribute to set in RM + :type name: string + + :param guids1: List of guids of RMs subjected to action + :type guids1: list + + :param action: Action to register (either START or STOP) + :type action: ResourceAction + + :param guids2: List of guids of RMs to we waited for + :type guids2: list + + :param state: State to wait for on RMs (STARTED, STOPPED, etc) + :type state: ResourceState + + :param time: Time to wait after guids2 has reached status + :type time: string + + """ + if isinstance(guids1, int): + guids1 = [guids1] + if isinstance(guids2, int): + guids2 = [guids2] + + for guid1 in guids1: + rm = self.get_resource(guid) + rm.set_with_conditions(name, value, guids2, state, time) +
    +
    [docs] def deploy(self, guids = None, wait_all_ready = True, group = None): + """ Deploys all ResourceManagers in the guids list. + + If the argument 'guids' is not given, all RMs with state NEW + are deployed. + + :param guids: List of guids of RMs to deploy + :type guids: list + + :param wait_all_ready: Wait until all RMs are ready in + order to start the RMs + :type guid: int + + :param group: Id of deployment group in which to deploy RMs + :type group: int + + """ + self.logger.debug(" ------- DEPLOY START ------ ") + + if not guids: + # If no guids list was passed, all 'NEW' RMs will be deployed + guids = [] + for guid, rm in self._resources.iteritems(): + if rm.state == ResourceState.NEW: + guids.append(guid) + + if isinstance(guids, int): + guids = [guids] + + # Create deployment group + # New guids can be added to a same deployment group later on + new_group = False + if not group: + new_group = True + group = self._group_id_generator.next() + + if group not in self._groups: + self._groups[group] = [] + + self._groups[group].extend(guids) + + def wait_all_and_start(group): + # Function that checks if all resources are READY + # before scheduling a start_with_conditions for each RM + reschedule = False + + # Get all guids in group + guids = self._groups[group] + + for guid in guids: + if self.state(guid) < ResourceState.READY: + reschedule = True + break + + if reschedule: + callback = functools.partial(wait_all_and_start, group) + self.schedule("1s", callback) + else: + # If all resources are ready, we schedule the start + for guid in guids: + rm = self.get_resource(guid) + self.schedule("0s", rm.start_with_conditions) + + if rm.conditions.get(ResourceAction.STOP): + # Only if the RM has STOP conditions we + # schedule a stop. Otherwise the RM will stop immediately + self.schedule("0s", rm.stop_with_conditions) + + if wait_all_ready and new_group: + # Schedule a function to check that all resources are + # READY, and only then schedule the start. + # This aims at reducing the number of tasks looping in the + # scheduler. + # Instead of having many start tasks, we will have only one for + # the whole group. + callback = functools.partial(wait_all_and_start, group) + self.schedule("0s", callback) + + for guid in guids: + rm = self.get_resource(guid) + rm.deployment_group = group + self.schedule("0s", rm.deploy_with_conditions) + + if not wait_all_ready: + self.schedule("0s", rm.start_with_conditions) + + if rm.conditions.get(ResourceAction.STOP): + # Only if the RM has STOP conditions we + # schedule a stop. Otherwise the RM will stop immediately + self.schedule("0s", rm.stop_with_conditions) +
    +
    [docs] def release(self, guids = None): + """ Releases all ResourceManagers in the guids list. + + If the argument 'guids' is not given, all RMs registered + in the experiment are released. + + :param guids: List of RM guids + :type guids: list + + """ + if self._state == ECState.RELEASED: + return + + if isinstance(guids, int): + guids = [guids] + + if not guids: + guids = self.resources + + for guid in guids: + rm = self.get_resource(guid) + self.schedule("0s", rm.release) + + self.wait_released(guids) + + if self.persist: + self.save() + + for guid in guids: + if self.get(guid, "hardRelease"): + self.remove_resource(guid)\ + + # Mark the EC state as RELEASED + self._state = ECState.RELEASED +
    +
    [docs] def shutdown(self): + """ Releases all resources and stops the ExperimentController + + """ + # If there was a major failure we can't exit gracefully + if self._state == ECState.FAILED: + raise RuntimeError("EC failure. Can not exit gracefully") + + # Remove all pending tasks from the scheduler queue + for tid in list(self._scheduler.pending): + self._scheduler.remove(tid) + + # Remove pending tasks from the workers queue + self._runner.empty() + + self.release() + + # Mark the EC state as TERMINATED + self._state = ECState.TERMINATED + + # Stop processing thread + self._stop = True + + # Notify condition to wake up the processing thread + self._notify() + + if self._thread.is_alive(): + self._thread.join() +
    +
    [docs] def schedule(self, date, callback, track = False): + """ Schedules a callback to be executed at time 'date'. + + :param date: string containing execution time for the task. + It can be expressed as an absolute time, using + timestamp format, or as a relative time matching + ^\d+.\d+(h|m|s|ms|us)$ + + :param callback: code to be executed for the task. Must be a + Python function, and receives args and kwargs + as arguments. + + :param track: if set to True, the task will be retrievable with + the get_task() method + + :return : The Id of the task + :rtype: int + + """ + timestamp = stabsformat(date) + task = Task(timestamp, callback) + task = self._scheduler.schedule(task) + + if track: + self._tasks[task.id] = task + + # Notify condition to wake up the processing thread + self._notify() + + return task.id +
    + def _process(self): + """ Process scheduled tasks. + + .. note:: + + Tasks are scheduled by invoking the schedule method with a target + callback and an execution time. + The schedule method creates a new Task object with that callback + and execution time, and pushes it into the '_scheduler' queue. + The execution time and the order of arrival of tasks are used + to order the tasks in the queue. + + The _process method is executed in an independent thread held by + the ExperimentController for as long as the experiment is running. + This method takes tasks from the '_scheduler' queue in a loop + and processes them in parallel using multithreading. + The environmental variable NEPI_NTHREADS can be used to control + the number of threads used to process tasks. The default value is + 50. + + To execute tasks in parallel, a ParallelRunner (PR) object is used. + This object keeps a pool of threads (workers), and a queue of tasks + scheduled for 'immediate' execution. + + On each iteration, the '_process' loop will take the next task that + is scheduled for 'future' execution from the '_scheduler' queue, + and if the execution time of that task is >= to the current time, + it will push that task into the PR for 'immediate execution'. + As soon as a worker is free, the PR will assign the next task to + that worker. + + Upon receiving a task to execute, each PR worker (thread) will + invoke the _execute method of the EC, passing the task as + argument. + The _execute method will then invoke task.callback inside a + try/except block. If an exception is raised by the tasks.callback, + it will be trapped by the try block, logged to standard error + (usually the console), and the task will be marked as failed. + + """ + + self._nthreads = int(os.environ.get("NEPI_NTHREADS", str(self._nthreads))) + self._runner = ParallelRun(maxthreads = self.nthreads) + self._runner.start() + + while not self._stop: + try: + self._cond.acquire() + + task = self._scheduler.next() + + if not task: + # No task to execute. Wait for a new task to be scheduled. + self._cond.wait() + else: + # The task timestamp is in the future. Wait for timeout + # or until another task is scheduled. + now = tnow() + if now < task.timestamp: + # Calculate timeout in seconds + timeout = tdiffsec(task.timestamp, now) + + # Re-schedule task with the same timestamp + self._scheduler.schedule(task) + + task = None + + # Wait timeout or until a new task awakes the condition + self._cond.wait(timeout) + + self._cond.release() + + if task: + # Process tasks in parallel + self._runner.put(self._execute, task) + except: + import traceback + err = traceback.format_exc() + self.logger.error("Error while processing tasks in the EC: %s" % err) + + # Set the EC to FAILED state + self._state = ECState.FAILED + + # Set the FailureManager failure level to EC failure + self._fm.set_ec_failure() + + self.logger.debug("Exiting the task processing loop ... ") + + self._runner.sync() + self._runner.destroy() + + def _execute(self, task): + """ Executes a single task. + + :param task: Object containing the callback to execute + :type task: Task + + """ + try: + # Invoke callback + task.result = task.callback() + task.status = TaskStatus.DONE + except: + import traceback + err = traceback.format_exc() + task.result = err + task.status = TaskStatus.ERROR + + self.logger.error("Error occurred while executing task: %s" % err) + + def _notify(self): + """ Awakes the processing thread if it is blocked waiting + for new tasks to arrive + + """ + self._cond.acquire() + self._cond.notify() + self._cond.release() + + def _build_from_netgraph(self, add_node_callback, add_edge_callback, + **kwargs): + """ Automates experiment description using a NetGraph instance. + """ + self._netgraph = NetGraph(**kwargs) + + if add_node_callback: + ### Add resources to the EC + for nid in self.netgraph.nodes(): + add_node_callback(self, nid) + + if add_edge_callback: + #### Add connections between resources + for nid1, nid2 in self.netgraph.edges(): + add_edge_callback(self, nid1, nid2) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/execution/resource.html b/doc/sphinx/_build/html/_modules/nepi/execution/resource.html new file mode 100644 index 00000000..dd535d73 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/execution/resource.html @@ -0,0 +1,1326 @@ + + + + + + + + nepi.execution.resource — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.execution.resource

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.util.timefuncs import tnow, tdiff, tdiffsec, stabsformat
    +from nepi.util.logger import Logger
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import TraceAttr
    +
    +import copy
    +import functools
    +import logging
    +import os
    +import pkgutil
    +import sys
    +import threading
    +import weakref
    +
    +
    [docs]class ResourceAction: + """ Action that a user can order to a Resource Manager + + """ + DEPLOY = 0 + START = 1 + STOP = 2 +
    +
    [docs]class ResourceState: + """ State of a Resource Manager + + """ + NEW = 0 + DISCOVERED = 1 + RESERVED = 2 + PROVISIONED = 3 + READY = 4 + STARTED = 5 + STOPPED = 6 + FAILED = 7 + RELEASED = 8 +
    +ResourceState2str = dict({ + ResourceState.NEW : "NEW", + ResourceState.DISCOVERED : "DISCOVERED", + ResourceState.RESERVED : "RESERVED", + ResourceState.PROVISIONED : "PROVISIONED", + ResourceState.READY : "READY", + ResourceState.STARTED : "STARTED", + ResourceState.STOPPED : "STOPPED", + ResourceState.FAILED : "FAILED", + ResourceState.RELEASED : "RELEASED", + }) + +
    [docs]def clsinit(cls): + """ Initializes template information (i.e. attributes and traces) + on classes derived from the ResourceManager class. + + It is used as a decorator in the class declaration as follows: + + @clsinit + class MyResourceManager(ResourceManager): + + ... + + """ + + cls._clsinit() + return cls +
    +
    [docs]def clsinit_copy(cls): + """ Initializes template information (i.e. attributes and traces) + on classes derived from the ResourceManager class. + It differs from the clsinit method in that it forces inheritance + of attributes and traces from the parent class. + + It is used as a decorator in the class declaration as follows: + + @clsinit + class MyResourceManager(ResourceManager): + + ... + + + clsinit_copy should be prefered to clsinit when creating new + ResourceManager child classes. + + """ + + cls._clsinit_copy() + return cls +
    +
    [docs]def failtrap(func): + """ Decorator function for instance methods that should set the + RM state to FAILED when an error is raised. The methods that must be + decorated are: discover, reserved, provision, deploy, start, stop. + + """ + def wrapped(self, *args, **kwargs): + try: + return func(self, *args, **kwargs) + except: + self.fail() + + import traceback + err = traceback.format_exc() + logger = Logger(self._rtype) + logger.error(err) + logger.error("SETTING guid %d to state FAILED" % self.guid) + raise + + return wrapped +
    +@clsinit +
    [docs]class ResourceManager(Logger): + """ Base clase for all ResourceManagers. + + A ResourceManger is specific to a resource type (e.g. Node, + Switch, Application, etc) on a specific platform (e.g. PlanetLab, + OMF, etc). + + The ResourceManager instances are responsible for interacting with + and controlling concrete (physical or virtual) resources in the + experimental platforms. + + """ + _rtype = "Resource" + _attributes = None + _traces = None + _help = None + _platform = None + _reschedule_delay = "0.5s" + + @classmethod + def _register_attribute(cls, attr): + """ Resource subclasses will invoke this method to add a + resource attribute + + """ + + cls._attributes[attr.name] = attr + + @classmethod + def _remove_attribute(cls, name): + """ Resource subclasses will invoke this method to remove a + resource attribute + + """ + + del cls._attributes[name] + + @classmethod + def _register_trace(cls, trace): + """ Resource subclasses will invoke this method to add a + resource trace + + """ + + cls._traces[trace.name] = trace + + @classmethod + def _remove_trace(cls, name): + """ Resource subclasses will invoke this method to remove a + resource trace + + """ + + del cls._traces[name] + + @classmethod + def _register_attributes(cls): + """ Resource subclasses will invoke this method to register + resource attributes. + + This method should be overriden in the RMs that define + attributes. + + """ + critical = Attribute("critical", + "Defines whether the resource is critical. " + "A failure on a critical resource will interrupt " + "the experiment. ", + type = Types.Bool, + default = True, + flags = Flags.Design) + hard_release = Attribute("hardRelease", + "Forces removal of all result files and directories associated " + "to the RM upon resource release. After release the RM will " + "be removed from the EC and the results will not longer be " + "accessible", + type = Types.Bool, + default = False, + flags = Flags.Design) + + cls._register_attribute(critical) + cls._register_attribute(hard_release) + + @classmethod + def _register_traces(cls): + """ Resource subclasses will invoke this method to register + resource traces + + This method should be overridden in the RMs that define traces. + + """ + + pass + + @classmethod + def _clsinit(cls): + """ ResourceManager classes have different attributes and traces. + Attribute and traces are stored in 'class attribute' dictionaries. + When a new ResourceManager class is created, the _clsinit method is + called to create a new instance of those dictionaries and initialize + them. + + The _clsinit method is called by the clsinit decorator method. + + """ + + # static template for resource attributes + cls._attributes = dict() + cls._register_attributes() + + # static template for resource traces + cls._traces = dict() + cls._register_traces() + + @classmethod + def _clsinit_copy(cls): + """ Same as _clsinit, except that after creating new instances of the + dictionaries it copies all the attributes and traces from the parent + class. + + The _clsinit_copy method is called by the clsinit_copy decorator method. + + """ + # static template for resource attributes + cls._attributes = copy.deepcopy(cls._attributes) + cls._register_attributes() + + # static template for resource traces + cls._traces = copy.deepcopy(cls._traces) + cls._register_traces() + + @classmethod +
    [docs] def get_rtype(cls): + """ Returns the type of the Resource Manager + + """ + return cls._rtype +
    + @classmethod +
    [docs] def get_attributes(cls): + """ Returns a copy of the attributes + + """ + return copy.deepcopy(cls._attributes.values()) +
    + @classmethod +
    [docs] def get_attribute(cls, name): + """ Returns a copy of the attribute with name 'name' + + """ + return copy.deepcopy(cls._attributes[name]) +
    + @classmethod +
    [docs] def get_traces(cls): + """ Returns a copy of the traces + + """ + return copy.deepcopy(cls._traces.values()) +
    + @classmethod +
    [docs] def get_help(cls): + """ Returns the description of the type of Resource + + """ + return cls._help +
    + @classmethod +
    [docs] def get_platform(cls): + """ Returns the identified of the platform (i.e. testbed type) + for the Resource + + """ + return cls._platform +
    + @classmethod +
    [docs] def get_global(cls, name): + """ Returns the value of a global attribute + Global attribute meaning an attribute for + all the resources from a rtype + + :param name: Name of the attribute + :type name: str + :rtype: str + """ + global_attr = cls._attributes[name] + return global_attr.value +
    + @classmethod +
    [docs] def set_global(cls, name, value): + """ Set value for a global attribute + + :param name: Name of the attribute + :type name: str + :param name: Value of the attribute + :type name: str + """ + global_attr = cls._attributes[name] + global_attr.value = value + return value +
    + def __init__(self, ec, guid): + super(ResourceManager, self).__init__(self.get_rtype()) + + self._guid = guid + self._ec = weakref.ref(ec) + self._connections = set() + self._conditions = dict() + + # the resource instance gets a copy of all attributes + self._attrs = copy.deepcopy(self._attributes) + + # the resource instance gets a copy of all traces + self._trcs = copy.deepcopy(self._traces) + + # Each resource is placed on a deployment group by the EC + # during deployment + self.deployment_group = None + + self._start_time = None + self._stop_time = None + self._discover_time = None + self._reserved_time = None + self._provision_time = None + self._ready_time = None + self._release_time = None + self._failed_time = None + + self._state = ResourceState.NEW + + # instance lock to synchronize exclusive state change methods (such + # as deploy and release methods), in order to prevent them from being + # executed at the same time and corrupt internal resource state + self._release_lock = threading.Lock() + + @property +
    [docs] def guid(self): + """ Returns the global unique identifier of the RM """ + return self._guid +
    + @property +
    [docs] def ec(self): + """ Returns the Experiment Controller of the RM """ + return self._ec() +
    + @property +
    [docs] def connections(self): + """ Returns the set of guids of connected RMs """ + return self._connections +
    + @property +
    [docs] def conditions(self): + """ Returns the conditions to which the RM is subjected to. + + This method returns a dictionary of conditions lists indexed by + a ResourceAction. + + """ + return self._conditions +
    + @property +
    [docs] def start_time(self): + """ Returns the start time of the RM as a timestamp """ + return self._start_time +
    + @property +
    [docs] def stop_time(self): + """ Returns the stop time of the RM as a timestamp """ + return self._stop_time +
    + @property +
    [docs] def discover_time(self): + """ Returns the discover time of the RM as a timestamp """ + return self._discover_time +
    + @property +
    [docs] def reserved_time(self): + """ Returns the reserved time of the RM as a timestamp """ + return self._reserved_time +
    + @property +
    [docs] def provision_time(self): + """ Returns the provision time of the RM as a timestamp """ + return self._provision_time +
    + @property +
    [docs] def ready_time(self): + """ Returns the deployment time of the RM as a timestamp """ + return self._ready_time +
    + @property +
    [docs] def release_time(self): + """ Returns the release time of the RM as a timestamp """ + return self._release_time +
    + @property +
    [docs] def failed_time(self): + """ Returns the time failure occurred for the RM as a timestamp """ + return self._failed_time +
    + @property +
    [docs] def state(self): + """ Get the current state of the RM """ + return self._state +
    + @property +
    [docs] def reschedule_delay(self): + """ Returns default reschedule delay """ + return self._reschedule_delay +
    +
    [docs] def log_message(self, msg): + """ Returns the log message formatted with added information. + + :param msg: text message + :type msg: str + :rtype: str + + """ + return " %s guid %d - %s " % (self._rtype, self.guid, msg) +
    +
    [docs] def register_connection(self, guid): + """ Registers a connection to the RM identified by guid + + This method should not be overridden. Specific functionality + should be added in the do_connect method. + + :param guid: Global unique identified of the RM to connect to + :type guid: int + + """ + if self.valid_connection(guid): + self.do_connect(guid) + self._connections.add(guid) +
    +
    [docs] def unregister_connection(self, guid): + """ Removes a registered connection to the RM identified by guid + + This method should not be overridden. Specific functionality + should be added in the do_disconnect method. + + :param guid: Global unique identified of the RM to connect to + :type guid: int + + """ + if guid in self._connections: + self.do_disconnect(guid) + self._connections.remove(guid) +
    + @failtrap +
    [docs] def discover(self): + """ Performs resource discovery. + + This method is responsible for selecting an individual resource + matching user requirements. + + This method should not be overridden directly. Specific functionality + should be added in the do_discover method. + + """ + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_discover() +
    + @failtrap +
    [docs] def reserve(self): + """ Performs resource reserve. + + This method is responsible for reserving an individual resource + matching user requirements. + + This method should not be overridden directly. Specific functionality + should be added in the do_reserved method. + + """ + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_reserve() +
    + @failtrap +
    [docs] def provision(self): + """ Performs resource provisioning. + + This method is responsible for provisioning one resource. + After this method has been successfully invoked, the resource + should be accessible/controllable by the RM. + + This method should not be overridden directly. Specific functionality + should be added in the do_provision method. + + """ + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_provision() +
    + @failtrap +
    [docs] def configure(self): + """ Performs resource configuration. + + This method is responsible for configuring one resource. + After this method has been successfully invoked, the resource + should be set up to start the experimentation. + + This method should not be overridden directly. Specific functionality + should be added in the do_configure method. + + """ + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_configure() +
    + @failtrap +
    [docs] def start(self): + """ Starts the RM (e.g. launch remote process). + + There is no standard start behavior. Some RMs will not need to perform + any actions upon start. + + This method should not be overridden directly. Specific functionality + should be added in the do_start method. + + """ + + if not self.state in [ResourceState.READY, ResourceState.STOPPED]: + self.error("Wrong state %s for start" % self.state) + return + + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_start() +
    + @failtrap +
    [docs] def stop(self): + """ Interrupts the RM, stopping any tasks the RM was performing. + + There is no standard stop behavior. Some RMs will not need to perform + any actions upon stop. + + This method should not be overridden directly. Specific functionality + should be added in the do_stop method. + + """ + if not self.state in [ResourceState.STARTED]: + self.error("Wrong state %s for stop" % self.state) + return + + with self._release_lock: + self.do_stop() +
    + @failtrap +
    [docs] def deploy(self): + """ Execute all steps required for the RM to reach the state READY. + + This method is responsible for deploying the resource (and invoking + the discover and provision methods). + + This method should not be overridden directly. Specific functionality + should be added in the do_deploy method. + + """ + if self.state > ResourceState.READY: + self.error("Wrong state %s for deploy" % self.state) + return + + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_deploy() +
    +
    [docs] def release(self): + """ Perform actions to free resources used by the RM. + + This method is responsible for releasing resources that were + used during the experiment by the RM. + + This method should not be overridden directly. Specific functionality + should be added in the do_release method. + + """ + with self._release_lock: + try: + self.do_release() + except: + self.set_released() + + import traceback + err = traceback.format_exc() + msg = " %s guid %d ----- FAILED TO RELEASE ----- \n %s " % ( + self._rtype, self.guid, err) + logger = Logger(self._rtype) + logger.debug(msg) +
    +
    [docs] def fail(self): + """ Sets the RM to state FAILED. + + This method should not be overridden directly. Specific functionality + should be added in the do_fail method. + + """ + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_fail() +
    +
    [docs] def set(self, name, value): + """ Set the value of the attribute + + :param name: Name of the attribute + :type name: str + :param name: Value of the attribute + :type name: str + """ + attr = self._attrs[name] + attr.value = value + return value +
    +
    [docs] def get(self, name): + """ Returns the value of the attribute + + :param name: Name of the attribute + :type name: str + :rtype: str + """ + attr = self._attrs[name] + + """ + A.Q. Commenting due to performance impact + if attr.has_flag(Flags.Global): + self.warning( "Attribute %s is global. Use get_global instead." % name) + """ + + return attr.value +
    +
    [docs] def has_changed(self, name): + """ Returns the True is the value of the attribute + has been modified by the user. + + :param name: Name of the attribute + :type name: str + :rtype: str + """ + attr = self._attrs[name] + return attr.has_changed +
    +
    [docs] def has_flag(self, name, flag): + """ Returns true if the attribute has the flag 'flag' + + :param flag: Flag to be checked + :type flag: Flags + """ + attr = self._attrs[name] + return attr.has_flag(flag) +
    +
    [docs] def has_attribute(self, name): + """ Returns true if the RM has an attribute with name + + :param name: name of the attribute + :type name: string + """ + return name in self._attrs +
    +
    [docs] def enable_trace(self, name): + """ Explicitly enable trace generation + + :param name: Name of the trace + :type name: str + """ + trace = self._trcs[name] + trace.enabled = True +
    +
    [docs] def trace_enabled(self, name): + """Returns True if trace is enables + + :param name: Name of the trace + :type name: str + """ + trace = self._trcs[name] + return trace.enabled +
    +
    [docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + """ Get information on collected trace + + :param name: Name of the trace + :type name: str + + :param attr: Can be one of: + - TraceAttr.ALL (complete trace content), + - TraceAttr.STREAM (block in bytes to read starting at offset), + - TraceAttr.PATH (full path to the trace file), + - TraceAttr.SIZE (size of trace file). + :type attr: str + + :param block: Number of bytes to retrieve from trace, when attr is TraceAttr.STREAM + :type name: int + + :param offset: Number of 'blocks' to skip, when attr is TraceAttr.STREAM + :type name: int + + :rtype: str + """ + pass +
    +
    [docs] def register_condition(self, action, group, state, time = None): + """ Registers a condition on the resource manager to allow execution + of 'action' only after 'time' has elapsed from the moment all resources + in 'group' reached state 'state' + + :param action: Action to restrict to condition (either 'START' or 'STOP') + :type action: str + :param group: Group of RMs to wait for (list of guids) + :type group: int or list of int + :param state: State to wait for on all RM in group. (either 'STARTED', 'STOPPED' or 'READY') + :type state: str + :param time: Time to wait after 'state' is reached on all RMs in group. (e.g. '2s') + :type time: str + + """ + + if not action in self.conditions: + self._conditions[action] = list() + + conditions = self.conditions.get(action) + + # For each condition to register a tuple of (group, state, time) is + # added to the 'action' list + if not isinstance(group, list): + group = [group] + + conditions.append((group, state, time)) +
    +
    [docs] def unregister_condition(self, group, action = None): + """ Removed conditions for a certain group of guids + + :param action: Action to restrict to condition (either 'START', 'STOP' or 'READY') + :type action: str + + :param group: Group of RMs to wait for (list of guids) + :type group: int or list of int + + """ + # For each condition a tuple of (group, state, time) is + # added to the 'action' list + if not isinstance(group, list): + group = [group] + + for act, conditions in self.conditions.iteritems(): + if action and act != action: + continue + + for condition in list(conditions): + (grp, state, time) = condition + + # If there is an intersection between grp and group, + # then remove intersected elements + intsec = set(group).intersection(set(grp)) + if intsec: + idx = conditions.index(condition) + newgrp = set(grp) + newgrp.difference_update(intsec) + conditions[idx] = (newgrp, state, time) +
    +
    [docs] def get_connected(self, rtype = None): + """ Returns the list of RM with the type 'rtype' + + :param rtype: Type of the RM we look for + :type rtype: str + :return: list of guid + """ + connected = [] + rclass = ResourceFactory.get_resource_type(rtype) + for guid in self.connections: + rm = self.ec.get_resource(guid) + if not rtype or isinstance(rm, rclass): + connected.append(rm) + return connected +
    +
    [docs] def is_rm_instance(self, rtype): + """ Returns True if the RM is instance of 'rtype' + + :param rtype: Type of the RM we look for + :type rtype: str + :return: True|False + """ + rclass = ResourceFactory.get_resource_type(rtype) + if isinstance(self, rclass): + return True + return False +
    + @failtrap + def _needs_reschedule(self, group, state, time): + """ Internal method that verify if 'time' has elapsed since + all elements in 'group' have reached state 'state'. + + :param group: Group of RMs to wait for (list of guids) + :type group: int or list of int + :param state: State to wait for on all RM in group. (either 'STARTED', 'STOPPED' or 'READY') + :type state: str + :param time: Time to wait after 'state' is reached on all RMs in group. (e.g. '2s') + :type time: str + + .. note : time should be written like "2s" or "3m" with s for seconds, m for minutes, h for hours, ... + If for example, you need to wait 2min 30sec, time could be "150s" or "2.5m". + For the moment, 2m30s is not a correct syntax. + + """ + reschedule = False + delay = self.reschedule_delay + + # check state and time elapsed on all RMs + for guid in group: + rm = self.ec.get_resource(guid) + + # If one of the RMs this resource needs to wait for has FAILED + # and is critical we raise an exception + if rm.state == ResourceState.FAILED: + if not rm.get('critical'): + continue + msg = "Resource can not wait for FAILED RM %d. Setting Resource to FAILED" + raise RuntimeError, msg + + # If the RM state is lower than the requested state we must + # reschedule (e.g. if RM is READY but we required STARTED). + if rm.state < state: + reschedule = True + break + + # If there is a time restriction, we must verify the + # restriction is satisfied + if time: + if state == ResourceState.DISCOVERED: + t = rm.discover_time + elif state == ResourceState.RESERVED: + t = rm.reserved_time + elif state == ResourceState.PROVISIONED: + t = rm.provision_time + elif state == ResourceState.READY: + t = rm.ready_time + elif state == ResourceState.STARTED: + t = rm.start_time + elif state == ResourceState.STOPPED: + t = rm.stop_time + elif state == ResourceState.RELEASED: + t = rm.release_time + else: + break + + # time already elapsed since RM changed state + waited = "%fs" % tdiffsec(tnow(), t) + + # time still to wait + wait = tdiffsec(stabsformat(time), stabsformat(waited)) + + if wait > 0.001: + reschedule = True + delay = "%fs" % wait + break + + return reschedule, delay + +
    [docs] def set_with_conditions(self, name, value, group, state, time): + """ Set value 'value' on attribute with name 'name' when 'time' + has elapsed since all elements in 'group' have reached state + 'state' + + :param name: Name of the attribute to set + :type name: str + :param name: Value of the attribute to set + :type name: str + :param group: Group of RMs to wait for (list of guids) + :type group: int or list of int + :param state: State to wait for on all RM in group. (either 'STARTED', 'STOPPED' or 'READY') + :type state: str + :param time: Time to wait after 'state' is reached on all RMs in group. (e.g. '2s') + :type time: str + """ + + reschedule = False + delay = self.reschedule_delay + + ## evaluate if set conditions are met + + # only can set with conditions after the RM is started + if self.state != ResourceState.STARTED: + reschedule = True + else: + reschedule, delay = self._needs_reschedule(group, state, time) + + if reschedule: + callback = functools.partial(self.set_with_conditions, + name, value, group, state, time) + self.ec.schedule(delay, callback) + else: + self.set(name, value) +
    +
    [docs] def start_with_conditions(self): + """ Starts RM when all the conditions in self.conditions for + action 'START' are satisfied. + + """ + #import pdb;pdb.set_trace() + + reschedule = False + delay = self.reschedule_delay + + + ## evaluate if conditions to start are met + if self.ec.abort: + return + + # Can only start when RM is either STOPPED or READY + if self.state not in [ResourceState.STOPPED, ResourceState.READY]: + reschedule = True + self.debug("---- RESCHEDULING START ---- state %s " % self.state ) + else: + start_conditions = self.conditions.get(ResourceAction.START, []) + + self.debug("---- START CONDITIONS ---- %s" % start_conditions) + + # Verify all start conditions are met + for (group, state, time) in start_conditions: + # Uncomment for debug + #unmet = [] + #for guid in group: + # rm = self.ec.get_resource(guid) + # unmet.append((guid, rm._state)) + # + #self.debug("---- WAITED STATES ---- %s" % unmet ) + + reschedule, delay = self._needs_reschedule(group, state, time) + if reschedule: + break + + if reschedule: + self.ec.schedule(delay, self.start_with_conditions) + else: + self.debug("----- STARTING ---- ") + self.start() +
    +
    [docs] def stop_with_conditions(self): + """ Stops RM when all the conditions in self.conditions for + action 'STOP' are satisfied. + + """ + reschedule = False + delay = self.reschedule_delay + + ## evaluate if conditions to stop are met + if self.ec.abort: + return + + # only can stop when RM is STARTED + if self.state != ResourceState.STARTED: + reschedule = True + self.debug("---- RESCHEDULING STOP ---- state %s " % self.state ) + else: + self.debug(" ---- STOP CONDITIONS ---- %s" % + self.conditions.get(ResourceAction.STOP)) + + stop_conditions = self.conditions.get(ResourceAction.STOP, []) + for (group, state, time) in stop_conditions: + reschedule, delay = self._needs_reschedule(group, state, time) + if reschedule: + break + + if reschedule: + callback = functools.partial(self.stop_with_conditions) + self.ec.schedule(delay, callback) + else: + self.debug(" ----- STOPPING ---- ") + self.stop() +
    +
    [docs] def deploy_with_conditions(self): + """ Deploy RM when all the conditions in self.conditions for + action 'READY' are satisfied. + + """ + reschedule = False + delay = self.reschedule_delay + + ## evaluate if conditions to deploy are met + if self.ec.abort: + return + + # only can deploy when RM is either NEW, DISCOVERED or PROVISIONED + if self.state not in [ResourceState.NEW, ResourceState.DISCOVERED, + ResourceState.RESERVED, ResourceState.PROVISIONED]: + #### XXX: A.Q. IT SHOULD FAIL IF DEPLOY IS CALLED IN OTHER STATES! + reschedule = True + self.debug("---- RESCHEDULING DEPLOY ---- state %s " % self.state ) + else: + deploy_conditions = self.conditions.get(ResourceAction.DEPLOY, []) + + self.debug("---- DEPLOY CONDITIONS ---- %s" % deploy_conditions) + + # Verify all start conditions are met + for (group, state, time) in deploy_conditions: + # Uncomment for debug + #unmet = [] + #for guid in group: + # rm = self.ec.get_resource(guid) + # unmet.append((guid, rm._state)) + + #self.debug("---- WAITED STATES ---- %s" % unmet ) + + reschedule, delay = self._needs_reschedule(group, state, time) + if reschedule: + break + + if reschedule: + self.ec.schedule(delay, self.deploy_with_conditions) + else: + self.debug("----- DEPLOYING ---- ") + self.deploy() +
    +
    [docs] def do_connect(self, guid): + """ Performs actions that need to be taken upon associating RMs. + This method should be redefined when necessary in child classes. + """ + pass +
    +
    [docs] def do_disconnect(self, guid): + """ Performs actions that need to be taken upon disassociating RMs. + This method should be redefined when necessary in child classes. + """ + pass +
    +
    [docs] def valid_connection(self, guid): + """Checks whether a connection with the other RM + is valid. + This method need to be redefined by each new Resource Manager. + + :param guid: Guid of the current Resource Manager + :type guid: int + :rtype: Boolean + + """ + # TODO: Validate! + return True +
    +
    [docs] def do_discover(self): + self.set_discovered() +
    +
    [docs] def do_reserve(self): + self.set_reserved() +
    +
    [docs] def do_provision(self): + self.set_provisioned() +
    +
    [docs] def do_configure(self): + pass +
    +
    [docs] def do_start(self): + self.set_started() +
    +
    [docs] def do_stop(self): + self.set_stopped() +
    +
    [docs] def do_deploy(self): + self.set_ready() +
    +
    [docs] def do_release(self): + self.set_released() +
    +
    [docs] def do_fail(self): + self.set_failed() + self.ec.inform_failure(self.guid) +
    +
    [docs] def set_started(self, time = None): + """ Mark ResourceManager as STARTED """ + self.set_state(ResourceState.STARTED, "_start_time", time) + self.debug("----- STARTED ---- ") +
    +
    [docs] def set_stopped(self, time = None): + """ Mark ResourceManager as STOPPED """ + self.set_state(ResourceState.STOPPED, "_stop_time", time) + self.debug("----- STOPPED ---- ") +
    +
    [docs] def set_ready(self, time = None): + """ Mark ResourceManager as READY """ + self.set_state(ResourceState.READY, "_ready_time", time) + self.debug("----- READY ---- ") +
    +
    [docs] def set_released(self, time = None): + """ Mark ResourceManager as REALEASED """ + self.set_state(ResourceState.RELEASED, "_release_time", time) + + msg = " %s guid %d ----- RELEASED ----- " % (self._rtype, self.guid) + logger = Logger(self._rtype) + logger.debug(msg) +
    +
    [docs] def set_failed(self, time = None): + """ Mark ResourceManager as FAILED """ + self.set_state(ResourceState.FAILED, "_failed_time", time) + + msg = " %s guid %d ----- FAILED ----- " % (self._rtype, self.guid) + logger = Logger(self._rtype) + logger.debug(msg) +
    +
    [docs] def set_discovered(self, time = None): + """ Mark ResourceManager as DISCOVERED """ + self.set_state(ResourceState.DISCOVERED, "_discover_time", time) + self.debug("----- DISCOVERED ---- ") +
    +
    [docs] def set_reserved(self, time = None): + """ Mark ResourceManager as RESERVED """ + self.set_state(ResourceState.RESERVED, "_reserved_time", time) + self.debug("----- RESERVED ---- ") +
    +
    [docs] def set_provisioned(self, time = None): + """ Mark ResourceManager as PROVISIONED """ + self.set_state(ResourceState.PROVISIONED, "_provision_time", time) + self.debug("----- PROVISIONED ---- ") +
    +
    [docs] def set_state(self, state, state_time_attr, time = None): + """ Set the state of the RM while keeping a trace of the time """ + + # Ensure that RM state will not change after released + if self._state == ResourceState.RELEASED: + return + + time = time or tnow() + self.set_state_time(state, state_time_attr, time) +
    +
    [docs] def set_state_time(self, state, state_time_attr, time): + """ Set the time for the RM state change """ + setattr(self, state_time_attr, time) + self._state = state +
    +
    [docs]class ResourceFactory(object): + _resource_types = dict() + + @classmethod +
    [docs] def resource_types(cls): + """Return the type of the Class""" + return cls._resource_types +
    + @classmethod +
    [docs] def get_resource_type(cls, rtype): + """Return the type of the Class""" + return cls._resource_types.get(rtype) +
    + @classmethod +
    [docs] def register_type(cls, rclass): + """Register a new Ressource Manager""" + cls._resource_types[rclass.get_rtype()] = rclass +
    + @classmethod +
    [docs] def create(cls, rtype, ec, guid): + """Create a new instance of a Ressource Manager""" + rclass = cls._resource_types[rtype] + return rclass(ec, guid) +
    +
    [docs]def populate_factory(): + """Find and rgister all available RMs + """ + # Once the factory is populated, don't repopulate + if not ResourceFactory.resource_types(): + for rclass in find_types(): + ResourceFactory.register_type(rclass) +
    +
    [docs]def find_types(): + """Look into the different folders to find all the + availables Resources Managers + """ + search_path = os.environ.get("NEPI_SEARCH_PATH", "") + search_path = set(search_path.split(" ")) + + import inspect + import nepi.resources + path = os.path.dirname(nepi.resources.__file__) + search_path.add(path) + + types = set() + + for importer, modname, ispkg in pkgutil.walk_packages(search_path, + prefix = "nepi.resources."): + + loader = importer.find_module(modname) + + try: + # Notice: Repeated calls to load_module will act as a reload of the module + if modname in sys.modules: + module = sys.modules.get(modname) + else: + module = loader.load_module(modname) + + for attrname in dir(module): + if attrname.startswith("_"): + continue + + attr = getattr(module, attrname) + + if attr == ResourceManager: + continue + + if not inspect.isclass(attr): + continue + + if issubclass(attr, ResourceManager): + types.add(attr) + + if not modname in sys.modules: + sys.modules[modname] = module + + except: + import traceback + import logging + err = traceback.format_exc() + logger = logging.getLogger("Resource.find_types()") + logger.error("Error while loading Resource Managers %s" % err) + + return types +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/execution/runner.html b/doc/sphinx/_build/html/_modules/nepi/execution/runner.html new file mode 100644 index 00000000..63b0f158 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/execution/runner.html @@ -0,0 +1,267 @@ + + + + + + + + nepi.execution.runner — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.execution.runner

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.ec import ExperimentController, ECState
    +
    +import math
    +import numpy
    +import os
    +import time
    +
    +
    [docs]class ExperimentRunner(object): + """ The ExperimentRunner entity is responsible of + re-running an experiment described by an ExperimentController + multiple time + + """ + def __init__(self): + super(ExperimentRunner, self).__init__() + +
    [docs] def run(self, ec, min_runs = 1, max_runs = -1, wait_time = 0, + wait_guids = [], compute_metric_callback = None, + evaluate_convergence_callback = None ): + """ Run a same experiment independently multiple times, until the + evaluate_convergence_callback function returns True + + :param ec: Description of experiment to replicate. + The runner takes care of deploying the EC, so ec.deploy() + must not be invoked directly before or after invoking + runner.run(). + :type ec: ExperimentController + + :param min_runs: Minimum number of times the experiment must be + replicated + :type min_runs: int + + :param max_runs: Maximum number of times the experiment can be + replicated + :type max_runs: int + + :param wait_time: Time to wait in seconds on each run between invoking + ec.deploy() and ec.release(). + :type wait_time: float + + :param wait_guids: List of guids wait for finalization on each run. + This list is passed to ec.wait_finished() + :type wait_guids: list + + :param compute_metric_callback: User defined function invoked after + each experiment run to compute a metric. The metric is usually + a network measurement obtained from the data collected + during experiment execution. + The function is invoked passing the ec and the run number as arguments. + It must return the value for the computed metric(s) (usually a single + numerical value, but it can be several). + + metric = compute_metric_callback(ec, run) + + :type compute_metric_callback: function + + :param evaluate_convergence_callback: User defined function invoked after + computing the metric on each run, to evaluate the experiment was + run enough times. It takes the list of cumulated metrics produced by + the compute_metric_callback up to the current run, and decided + whether the metrics have statistically converged to a meaningful value + or not. It must return either True or False. + + stop = evaluate_convergence_callback(ec, run, metrics) + + If stop is True, then the runner will exit. + + :type evaluate_convergence_callback: function + + """ + + if (not max_runs or max_runs < 0) and not compute_metric_callback: + msg = "Undefined STOP condition, set stop_callback or max_runs" + raise RuntimeError, msg + + if compute_metric_callback and not evaluate_convergence_callback: + evaluate_convergence_callback = self.evaluate_normal_convergence + ec.logger.info(" Treating data as normal to evaluate convergence. " + "Experiment will stop when the standard error with 95% " + "confidence interval is >= 5% of the mean of the collected samples ") + + # Force persistence of experiment controller + ec._persist = True + + filepath = ec.save(dirpath = ec.exp_dir) + + samples = [] + run = 0 + stop = False + + while not stop: + run += 1 + + ec = self.run_experiment(filepath, wait_time, wait_guids) + + ec.logger.info(" RUN %d \n" % run) + + if compute_metric_callback: + metric = compute_metric_callback(ec, run) + if metric is not None: + samples.append(metric) + + if run >= min_runs and evaluate_convergence_callback: + if evaluate_convergence_callback(ec, run, samples): + stop = True + + if run >= min_runs and max_runs > -1 and run >= max_runs : + stop = True + + ec.shutdown() + del ec + + return run +
    +
    [docs] def evaluate_normal_convergence(self, ec, run, metrics): + """ Returns True when the confidence interval of the sample mean is + less than 5% of the mean value, for a 95% confidence level, + assuming normal distribution of the data + """ + + if len(metrics) == 0: + msg = "0 samples collected" + raise RuntimeError, msg + + x = numpy.array(metrics) + n = len(metrics) + std = x.std() + se = std / math.sqrt(n) + m = x.mean() + + # Confidence interval for 95% confidence level, + # assuming normally distributed data. + ci95 = se * 2 + + ec.logger.info(" RUN %d - SAMPLES %d MEAN %.2f STD %.2f CI (95%%) %.2f \n" % ( + run, n, m, std, ci95 ) ) + + return m * 0.05 >= ci95 +
    +
    [docs] def run_experiment(self, filepath, wait_time, wait_guids): + """ Run an experiment based on the description stored + in filepath. + + """ + ec = ExperimentController.load(filepath) + + ec.deploy() + + ec.wait_finished(wait_guids) + time.sleep(wait_time) + + ec.release() + + if ec.state == ECState.FAILED: + raise RuntimeError, "Experiment failed" + + return ec +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/execution/scheduler.html b/doc/sphinx/_build/html/_modules/nepi/execution/scheduler.html new file mode 100644 index 00000000..f5ff0e15 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/execution/scheduler.html @@ -0,0 +1,201 @@ + + + + + + + + nepi.execution.scheduler — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.execution.scheduler

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import itertools
    +import heapq
    +
    +
    [docs]class TaskStatus: + """ Execution state of the Task + """ + NEW = 0 + DONE = 1 + ERROR = 2 +
    +
    [docs]class Task(object): + """ A Task represents an operation to be executed by the + ExperimentController scheduler + """ + + def __init__(self, timestamp, callback): + """ + :param timestamp: Future execution date of the operation + :type timestamp: str + + :param callback: A function to invoke in order to execute the operation + :type callback: function + + """ + self.id = None + self.timestamp = timestamp + self.callback = callback + self.result = None + self.status = TaskStatus.NEW +
    +
    [docs]class HeapScheduler(object): + """ Create a Heap Scheduler + + .. note:: + + This class is thread safe. + All calls to C Extensions are made atomic by the GIL in the CPython implementation. + heapq.heappush, heapq.heappop, and list access are therefore thread-safe. + + """ + + def __init__(self): + super(HeapScheduler, self).__init__() + self._queue = list() + self._valid = set() + self._idgen = itertools.count(1) + + @property +
    [docs] def pending(self): + """ Returns the list of pending task ids """ + return self._valid +
    +
    [docs] def schedule(self, task): + """ Add a task to the queue ordered by task.timestamp and arrival order + + :param task: task to schedule + :type task: task + """ + if task.id == None: + task.id = self._idgen.next() + + entry = (task.timestamp, task.id, task) + self._valid.add(task.id) + heapq.heappush(self._queue, entry) + return task +
    +
    [docs] def remove(self, tid): + """ Remove a task form the queue + + :param tid: Id of the task to be removed + :type tid: int + + """ + try: + self._valid.remove(tid) + except: + pass +
    +
    [docs] def next(self): + """ Get the next task in the queue by timestamp and arrival order + """ + while self._queue: + try: + timestamp, tid, task = heapq.heappop(self._queue) + if tid in self._valid: + self.remove(tid) + return task + except IndexError: + # heap empty + pass + return None +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/execution/trace.html b/doc/sphinx/_build/html/_modules/nepi/execution/trace.html new file mode 100644 index 00000000..dfe0bb19 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/execution/trace.html @@ -0,0 +1,148 @@ + + + + + + + + nepi.execution.trace — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.execution.trace

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +
    [docs]class TraceAttr: + """A Trace attribute defines information about a Trace that can + be queried + """ + ALL = "all" + STREAM = "stream" + PATH = "path" + SIZE = "size" +
    +
    [docs]class Trace(object): + """ A Trace represents information about a Resource that can + be collected + """ + + def __init__(self, name, help, enabled = False): + """ + :param name: Name of the Trace + :type name: str + + :param help: Description of the Trace + :type help: str + + :param enabled: Sets activation state of Trace + :type enabled: bool + """ + self._name = name + self._help = help + self.enabled = enabled + + @property +
    [docs] def name(self): + """ Returns the name of the trace """ + return self._name +
    + @property +
    [docs] def help(self): + """ Returns the help of the trace """ + return self._help +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/all/collector.html b/doc/sphinx/_build/html/_modules/nepi/resources/all/collector.html new file mode 100644 index 00000000..55ec554d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/all/collector.html @@ -0,0 +1,227 @@ + + + + + + + + nepi.resources.all.collector — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.all.collector

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState, ResourceAction
    +from nepi.util.sshfuncs import ProcStatus
    +
    +import os
    +import tempfile
    +
    +@clsinit_copy
    +
    [docs]class Collector(ResourceManager): + """ The collector entity is reponsible of collecting traces + of a same type associated to RMs into a local directory. + + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + _rtype = "Collector" + _help = "A Collector can be attached to a trace name on another " \ + "ResourceManager and will retrieve and store the trace content " \ + "in a local file at the end of the experiment" + _platform = "all" + + @classmethod + def _register_attributes(cls): + trace_name = Attribute("traceName", + "Name of the trace to be collected", + flags = Flags.Design) + + sub_dir = Attribute("subDir", + "Sub directory to collect traces into", + flags = Flags.Design) + + rename = Attribute("rename", + "Name to give to the collected trace file", + flags = Flags.Design) + + cls._register_attribute(trace_name) + cls._register_attribute(sub_dir) + cls._register_attribute(rename) + + def __init__(self, ec, guid): + super(Collector, self).__init__(ec, guid) + self._store_path = None + + @property +
    [docs] def store_path(self): + return self._store_path +
    +
    [docs] def do_provision(self): + trace_name = self.get("traceName") + if not trace_name: + self.fail() + + msg = "No traceName was specified" + self.error(msg) + raise RuntimeError, msg + + self._store_path = self.ec.run_dir + + subdir = self.get("subDir") + if subdir: + self._store_path = os.path.join(self.store_path, subdir) + + msg = "Creating local directory at %s to store %s traces " % ( + self.store_path, trace_name) + self.info(msg) + + try: + os.makedirs(self.store_path) + except OSError: + pass + + super(Collector, self).do_provision() +
    +
    [docs] def do_deploy(self): + self.do_discover() + self.do_provision() + + super(Collector, self).do_deploy() +
    +
    [docs] def do_release(self): + trace_name = self.get("traceName") + rename = self.get("rename") or trace_name + + msg = "Collecting '%s' traces to local directory %s" % ( + trace_name, self.store_path) + self.info(msg) + + rms = self.get_connected() + for rm in rms: + fpath = os.path.join(self.store_path, "%d.%s" % (rm.guid, + rename)) + + try: + result = self.ec.trace(rm.guid, trace_name) + f = open(fpath, "w") + f.write(result) + f.close() + except: + import traceback + err = traceback.format_exc() + msg = "Couldn't retrieve trace %s for %d at %s " % (trace_name, + rm.guid, fpath) + self.error(msg, out = "", err = err) + continue + + super(Collector, self).do_release() +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/application.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/application.html new file mode 100644 index 00000000..37493562 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/application.html @@ -0,0 +1,860 @@ + + + + + + + + nepi.resources.linux.application — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.application

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.linux.node import LinuxNode
    +from nepi.util.sshfuncs import ProcStatus
    +from nepi.util.timefuncs import tnow, tdiffsec
    +
    +import os
    +import subprocess
    +
    +# TODO: Resolve wildcards in commands!!
    +# TODO: When a failure occurs during deployment, scp and ssh processes are left running behind!!
    +
    +@clsinit_copy
    +
    [docs]class LinuxApplication(ResourceManager): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + .. note:: + + A LinuxApplication RM represents a process that can be executed in + a remote Linux host using SSH. + + The LinuxApplication RM takes care of uploadin sources and any files + needed to run the experiment, to the remote host. + It also allows to provide source compilation (build) and installation + instructions, and takes care of automating the sources build and + installation tasks for the user. + + It is important to note that files uploaded to the remote host have + two possible scopes: single-experiment or multi-experiment. + Single experiment files are those that will not be re-used by other + experiments. Multi-experiment files are those that will. + Sources and shared files are always made available to all experiments. + + Directory structure: + + The directory structure used by LinuxApplication RM at the Linux + host is the following: + + ${HOME}/.nepi/nepi-usr --> Base directory for multi-experiment files + | + ${LIB} |- /lib --> Base directory for libraries + ${BIN} |- /bin --> Base directory for binary files + ${SRC} |- /src --> Base directory for sources + ${SHARE} |- /share --> Base directory for other files + + ${HOME}/.nepi/nepi-exp --> Base directory for single-experiment files + | + ${EXP_HOME} |- /<exp-id> --> Base directory for experiment exp-id + | + ${APP_HOME} |- /<app-guid> --> Base directory for application + | specific files (e.g. command.sh, input) + | + ${RUN_HOME} |- /<run-id> --> Base directory for run specific + + """ + + _rtype = "linux::Application" + _help = "Runs an application on a Linux host with a BASH command " + _platform = "linux" + + @classmethod + def _register_attributes(cls): + command = Attribute("command", "Command to execute at application start. " + "Note that commands will be executed in the ${RUN_HOME} directory, " + "make sure to take this into account when using relative paths. ", + flags = Flags.Design) + forward_x11 = Attribute("forwardX11", "Enables X11 forwarding for SSH connections", + flags = Flags.Design) + env = Attribute("env", "Environment variables string for command execution", + flags = Flags.Design) + sudo = Attribute("sudo", "Run with root privileges", + flags = Flags.Design) + depends = Attribute("depends", + "Space-separated list of packages required to run the application", + flags = Flags.Design) + sources = Attribute("sources", + "semi-colon separated list of regular files to be uploaded to ${SRC} " + "directory prior to building. Archives won't be expanded automatically. " + "Sources are globally available for all experiments unless " + "cleanHome is set to True (This will delete all sources). ", + flags = Flags.Design) + files = Attribute("files", + "semi-colon separated list of regular miscellaneous files to be uploaded " + "to ${SHARE} directory. " + "Files are globally available for all experiments unless " + "cleanHome is set to True (This will delete all files). ", + flags = Flags.Design) + libs = Attribute("libs", + "semi-colon separated list of libraries (e.g. .so files) to be uploaded " + "to ${LIB} directory. " + "Libraries are globally available for all experiments unless " + "cleanHome is set to True (This will delete all files). ", + flags = Flags.Design) + bins = Attribute("bins", + "semi-colon separated list of binary files to be uploaded " + "to ${BIN} directory. " + "Binaries are globally available for all experiments unless " + "cleanHome is set to True (This will delete all files). ", + flags = Flags.Design) + code = Attribute("code", + "Plain text source code to be uploaded to the ${APP_HOME} directory. ", + flags = Flags.Design) + build = Attribute("build", + "Build commands to execute after deploying the sources. " + "Sources are uploaded to the ${SRC} directory and code " + "is uploaded to the ${APP_HOME} directory. \n" + "Usage example: tar xzf ${SRC}/my-app.tgz && cd my-app && " + "./configure && make && make clean.\n" + "Make sure to make the build commands return with a nonzero exit " + "code on error.", + flags = Flags.Design) + install = Attribute("install", + "Commands to transfer built files to their final destinations. " + "Install commands are executed after build commands. ", + flags = Flags.Design) + stdin = Attribute("stdin", "Standard input for the 'command'", + flags = Flags.Design) + tear_down = Attribute("tearDown", "Command to be executed just before " + "releasing the resource", + flags = Flags.Design) + + cls._register_attribute(command) + cls._register_attribute(forward_x11) + cls._register_attribute(env) + cls._register_attribute(sudo) + cls._register_attribute(depends) + cls._register_attribute(sources) + cls._register_attribute(code) + cls._register_attribute(files) + cls._register_attribute(bins) + cls._register_attribute(libs) + cls._register_attribute(build) + cls._register_attribute(install) + cls._register_attribute(stdin) + cls._register_attribute(tear_down) + + @classmethod + def _register_traces(cls): + stdout = Trace("stdout", "Standard output stream", enabled = True) + stderr = Trace("stderr", "Standard error stream", enabled = True) + + cls._register_trace(stdout) + cls._register_trace(stderr) + + def __init__(self, ec, guid): + super(LinuxApplication, self).__init__(ec, guid) + self._pid = None + self._ppid = None + self._node = None + self._home = "app-%s" % self.guid + + # whether the command should run in foreground attached + # to a terminal + self._in_foreground = False + + # whether to use sudo to kill the application process + self._sudo_kill = False + + # keep a reference to the running process handler when + # the command is not executed as remote daemon in background + self._proc = None + + # timestamp of last state check of the application + self._last_state_check = tnow() + +
    [docs] def log_message(self, msg): + return " guid %d - host %s - %s " % (self.guid, + self.node.get("hostname"), msg) +
    + @property +
    [docs] def node(self): + if not self._node: + node = self.get_connected(LinuxNode.get_rtype()) + if not node: + msg = "Application %s guid %d NOT connected to Node" % ( + self._rtype, self.guid) + raise RuntimeError, msg + + self._node = node[0] + + return self._node +
    + @property +
    [docs] def app_home(self): + return os.path.join(self.node.exp_home, self._home) +
    + @property +
    [docs] def run_home(self): + return os.path.join(self.app_home, self.ec.run_id) +
    + @property +
    [docs] def pid(self): + return self._pid +
    + @property +
    [docs] def ppid(self): + return self._ppid +
    + @property +
    [docs] def in_foreground(self): + """ Returns True if the command needs to be executed in foreground. + This means that command will be executed using 'execute' instead of + 'run' ('run' executes a command in background and detached from the + terminal) + + When using X11 forwarding option, the command can not run in background + and detached from a terminal, since we need to keep the terminal attached + to interact with it. + """ + return self.get("forwardX11") or self._in_foreground +
    +
    [docs] def trace_filepath(self, filename): + return os.path.join(self.run_home, filename) +
    +
    [docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + self.info("Retrieving '%s' trace %s " % (name, attr)) + + path = self.trace_filepath(name) + + command = "(test -f %s && echo 'success') || echo 'error'" % path + (out, err), proc = self.node.execute(command) + + if (err and proc.poll()) or out.find("error") != -1: + msg = " Couldn't find trace %s " % name + self.error(msg, out, err) + return None + + if attr == TraceAttr.PATH: + return path + + if attr == TraceAttr.ALL: + (out, err), proc = self.node.check_output(self.run_home, name) + + if proc.poll(): + msg = " Couldn't read trace %s " % name + self.error(msg, out, err) + return None + + return out + + if attr == TraceAttr.STREAM: + cmd = "dd if=%s bs=%d count=1 skip=%d" % (path, block, offset) + elif attr == TraceAttr.SIZE: + cmd = "stat -c%%s %s " % path + + (out, err), proc = self.node.execute(cmd) + + if proc.poll(): + msg = " Couldn't find trace %s " % name + self.error(msg, out, err) + return None + + if attr == TraceAttr.SIZE: + out = int(out.strip()) + + return out +
    +
    [docs] def do_provision(self): + # take a snapshot of the system if user is root + # to ensure that cleanProcess will not kill + # pre-existent processes + if self.node.get("username") == 'root': + import pickle + procs = dict() + ps_aux = "ps aux |awk '{print $2,$11}'" + (out, err), proc = self.node.execute(ps_aux) + if len(out) != 0: + for line in out.strip().split("\n"): + parts = line.strip().split(" ") + procs[parts[0]] = parts[1] + pickle.dump(procs, open("/tmp/save.proc", "wb")) + + # create run dir for application + self.node.mkdir(self.run_home) + + # List of all the provision methods to invoke + steps = [ + # upload sources + self.upload_sources, + # upload files + self.upload_files, + # upload binaries + self.upload_binaries, + # upload libraries + self.upload_libraries, + # upload code + self.upload_code, + # upload stdin + self.upload_stdin, + # install dependencies + self.install_dependencies, + # build + self.build, + # Install + self.install] + + command = [] + + # Since provisioning takes a long time, before + # each step we check that the EC is still + for step in steps: + if self.ec.abort: + self.debug("Interrupting provisioning. EC says 'ABORT") + return + + ret = step() + if ret: + command.append(ret) + + # upload deploy script + deploy_command = ";".join(command) + self.execute_deploy_command(deploy_command) + + # upload start script + self.upload_start_command() + + self.info("Provisioning finished") + + super(LinuxApplication, self).do_provision() +
    +
    [docs] def upload_start_command(self, overwrite = False): + # Upload command to remote bash script + # - only if command can be executed in background and detached + command = self.get("command") + + if command and not self.in_foreground: + self.info("Uploading command '%s'" % command) + + # replace application specific paths in the command + command = self.replace_paths(command) + # replace application specific paths in the environment + env = self.get("env") + env = env and self.replace_paths(env) + + shfile = os.path.join(self.app_home, "start.sh") + + self.node.upload_command(command, + shfile = shfile, + env = env, + overwrite = overwrite) +
    +
    [docs] def execute_deploy_command(self, command, prefix="deploy"): + if command: + # replace application specific paths in the command + command = self.replace_paths(command) + + # replace application specific paths in the environment + env = self.get("env") + env = env and self.replace_paths(env) + + # Upload the command to a bash script and run it + # in background ( but wait until the command has + # finished to continue ) + shfile = os.path.join(self.app_home, "%s.sh" % prefix) + self.node.run_and_wait(command, self.run_home, + shfile = shfile, + overwrite = False, + pidfile = "%s_pidfile" % prefix, + ecodefile = "%s_exitcode" % prefix, + stdout = "%s_stdout" % prefix, + stderr = "%s_stderr" % prefix) +
    +
    [docs] def upload_sources(self, sources = None, src_dir = None): + if not sources: + sources = self.get("sources") + + command = "" + + if not src_dir: + src_dir = self.node.src_dir + + if sources: + self.info("Uploading sources ") + + sources = map(str.strip, sources.split(";")) + + # Separate sources that should be downloaded from + # the web, from sources that should be uploaded from + # the local machine + command = [] + for source in list(sources): + if source.startswith("http") or source.startswith("https"): + # remove the hhtp source from the sources list + sources.remove(source) + + command.append( " ( " + # Check if the source already exists + " ls %(src_dir)s/%(basename)s " + " || ( " + # If source doesn't exist, download it and check + # that it it downloaded ok + " wget -c --directory-prefix=%(src_dir)s %(source)s && " + " ls %(src_dir)s/%(basename)s " + " ) ) " % { + "basename": os.path.basename(source), + "source": source, + "src_dir": src_dir + }) + + command = " && ".join(command) + + # replace application specific paths in the command + command = self.replace_paths(command) + + if sources: + sources = ';'.join(sources) + self.node.upload(sources, src_dir, overwrite = False) + + return command +
    +
    [docs] def upload_files(self, files = None): + if not files: + files = self.get("files") + + if files: + self.info("Uploading files %s " % files) + self.node.upload(files, self.node.share_dir, overwrite = False) +
    +
    [docs] def upload_libraries(self, libs = None): + if not libs: + libs = self.get("libs") + + if libs: + self.info("Uploading libraries %s " % libaries) + self.node.upload(libs, self.node.lib_dir, overwrite = False) +
    +
    [docs] def upload_binaries(self, bins = None): + if not bins: + bins = self.get("bins") + + if bins: + self.info("Uploading binaries %s " % binaries) + self.node.upload(bins, self.node.bin_dir, overwrite = False) +
    +
    [docs] def upload_code(self, code = None): + if not code: + code = self.get("code") + + if code: + self.info("Uploading code") + + dst = os.path.join(self.app_home, "code") + self.node.upload(code, dst, overwrite = False, text = True) +
    +
    [docs] def upload_stdin(self, stdin = None): + if not stdin: + stdin = self.get("stdin") + + if stdin: + # create dir for sources + self.info("Uploading stdin") + + # upload stdin file to ${SHARE_DIR} directory + if os.path.isfile(stdin): + basename = os.path.basename(stdin) + dst = os.path.join(self.node.share_dir, basename) + else: + dst = os.path.join(self.app_home, "stdin") + + self.node.upload(stdin, dst, overwrite = False, text = True) + + # create "stdin" symlink on ${APP_HOME} directory + command = "( cd %(app_home)s ; [ ! -f stdin ] && ln -s %(stdin)s stdin )" % ({ + "app_home": self.app_home, + "stdin": dst }) + + return command +
    +
    [docs] def install_dependencies(self, depends = None): + if not depends: + depends = self.get("depends") + + if depends: + self.info("Installing dependencies %s" % depends) + return self.node.install_packages_command(depends) +
    +
    [docs] def build(self, build = None): + if not build: + build = self.get("build") + + if build: + self.info("Building sources ") + + # replace application specific paths in the command + return self.replace_paths(build) +
    +
    [docs] def install(self, install = None): + if not install: + install = self.get("install") + + if install: + self.info("Installing sources ") + + # replace application specific paths in the command + return self.replace_paths(install) +
    +
    [docs] def do_deploy(self): + # Wait until node is associated and deployed + node = self.node + if not node or node.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + command = self.get("command") or "" + self.info("Deploying command '%s' " % command) + self.do_discover() + self.do_provision() + + super(LinuxApplication, self).do_deploy() +
    +
    [docs] def do_start(self): + command = self.get("command") + + self.info("Starting command '%s'" % command) + + if not command: + # If no command was given (i.e. Application was used for dependency + # installation), then the application is directly marked as STOPPED + super(LinuxApplication, self).set_stopped() + else: + if self.in_foreground: + self._run_in_foreground() + else: + self._run_in_background() + + super(LinuxApplication, self).do_start() +
    + def _run_in_foreground(self): + command = self.get("command") + sudo = self.get("sudo") or False + x11 = self.get("forwardX11") + env = self.get("env") + + # Command will be launched in foreground and attached to the + # terminal using the node 'execute' in non blocking mode. + + # We save the reference to the process in self._proc + # to be able to kill the process from the stop method. + # We also set blocking = False, since we don't want the + # thread to block until the execution finishes. + (out, err), self._proc = self.execute_command(command, + env = env, + sudo = sudo, + forward_x11 = x11, + blocking = False) + + if self._proc.poll(): + self.error(msg, out, err) + raise RuntimeError, msg + + def _run_in_background(self): + command = self.get("command") + env = self.get("env") + sudo = self.get("sudo") or False + + stdout = "stdout" + stderr = "stderr" + stdin = os.path.join(self.app_home, "stdin") if self.get("stdin") \ + else None + + # Command will be run as a daemon in baground and detached from any + # terminal. + # The command to run was previously uploaded to a bash script + # during deployment, now we launch the remote script using 'run' + # method from the node. + cmd = "bash %s" % os.path.join(self.app_home, "start.sh") + (out, err), proc = self.node.run(cmd, self.run_home, + stdin = stdin, + stdout = stdout, + stderr = stderr, + sudo = sudo) + + # check if execution errors occurred + msg = " Failed to start command '%s' " % command + + if proc.poll(): + self.error(msg, out, err) + raise RuntimeError, msg + + # Wait for pid file to be generated + pid, ppid = self.node.wait_pid(self.run_home) + if pid: self._pid = int(pid) + if ppid: self._ppid = int(ppid) + + # If the process is not running, check for error information + # on the remote machine + if not self.pid or not self.ppid: + (out, err), proc = self.node.check_errors(self.run_home, + stderr = stderr) + + # Out is what was written in the stderr file + if err: + msg = " Failed to start command '%s' " % command + self.error(msg, out, err) + raise RuntimeError, msg + +
    [docs] def do_stop(self): + """ Stops application execution + """ + command = self.get('command') or '' + + if self.state == ResourceState.STARTED: + + self.info("Stopping command '%s' " % command) + + # If the command is running in foreground (it was launched using + # the node 'execute' method), then we use the handler to the Popen + # process to kill it. Else we send a kill signal using the pid and ppid + # retrieved after running the command with the node 'run' method + if self._proc: + self._proc.kill() + else: + # Only try to kill the process if the pid and ppid + # were retrieved + if self.pid and self.ppid: + (out, err), proc = self.node.kill(self.pid, self.ppid, + sudo = self._sudo_kill) + + """ + # TODO: check if execution errors occurred + if (proc and proc.poll()) or err: + msg = " Failed to STOP command '%s' " % self.get("command") + self.error(msg, out, err) + """ + + super(LinuxApplication, self).do_stop() +
    +
    [docs] def do_release(self): + self.info("Releasing resource") + + self.do_stop() + + tear_down = self.get("tearDown") + if tear_down: + self.node.execute(tear_down) + + hard_release = self.get("hardRelease") + if hard_release: + self.node.rmdir(self.app_home) + + super(LinuxApplication, self).do_release() +
    + @property +
    [docs] def state(self): + """ Returns the state of the application + """ + if self._state == ResourceState.STARTED: + if self.in_foreground: + # Check if the process we used to execute the command + # is still running ... + retcode = self._proc.poll() + + # retcode == None -> running + # retcode > 0 -> error + # retcode == 0 -> finished + if retcode: + out = "" + msg = " Failed to execute command '%s'" % self.get("command") + err = self._proc.stderr.read() + self.error(msg, out, err) + self.do_fail() + + elif retcode == 0: + self.set_stopped() + else: + # We need to query the status of the command we launched in + # background. In order to avoid overwhelming the remote host and + # the local processor with too many ssh queries, the state is only + # requested every 'state_check_delay' seconds. + state_check_delay = 0.5 + if tdiffsec(tnow(), self._last_state_check) > state_check_delay: + if self.pid and self.ppid: + # Make sure the process is still running in background + status = self.node.status(self.pid, self.ppid) + + if status == ProcStatus.FINISHED: + # If the program finished, check if execution + # errors occurred + (out, err), proc = self.node.check_errors( + self.run_home) + + if err: + msg = "Failed to execute command '%s'" % \ + self.get("command") + self.error(msg, out, err) + self.do_fail() + else: + self.set_stopped() + + self._last_state_check = tnow() + + return self._state +
    +
    [docs] def execute_command(self, command, + env=None, + sudo=False, + tty=False, + forward_x11=False, + blocking=False): + + environ = "" + if env: + environ = self.node.format_environment(env, inline=True) + command = environ + command + command = self.replace_paths(command) + + return self.node.execute(command, + sudo=sudo, + tty=tty, + forward_x11=forward_x11, + blocking=blocking) +
    +
    [docs] def replace_paths(self, command, node=None, app_home=None, run_home=None): + """ + Replace all special path tags with shell-escaped actual paths. + """ + if not node: + node=self.node + + if not app_home: + app_home=self.app_home + + if not run_home: + run_home = self.run_home + + return ( command + .replace("${USR}", node.usr_dir) + .replace("${LIB}", node.lib_dir) + .replace("${BIN}", node.bin_dir) + .replace("${SRC}", node.src_dir) + .replace("${SHARE}", node.share_dir) + .replace("${EXP}", node.exp_dir) + .replace("${EXP_HOME}", node.exp_home) + .replace("${APP_HOME}", app_home) + .replace("${RUN_HOME}", run_home) + .replace("${NODE_HOME}", node.node_home) + .replace("${HOME}", node.home_dir) + ) +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnapplication.html new file mode 100644 index 00000000..b46dd26e --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnapplication.html @@ -0,0 +1,159 @@ + + + + + + + + nepi.resources.linux.ccn.ccnapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ccn.ccnapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.resources.linux.ccn.ccnd import LinuxCCND
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxCCNApplication(LinuxApplication): + _rtype = "linux::CCNApplication" + + def __init__(self, ec, guid): + super(LinuxCCNApplication, self).__init__(ec, guid) + self._home = "ccnapp-%s" % self.guid + + @property +
    [docs] def ccnd(self): + ccnd = self.get_connected(LinuxCCND.get_rtype()) + if ccnd: return ccnd[0] + return None +
    + @property +
    [docs] def node(self): + if self.ccnd: return self.ccnd.node + return None +
    +
    [docs] def do_deploy(self): + if not self.ccnd or self.ccnd.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + command = self.get("command") or "" + + self.info("Deploying command '%s' " % command) + + if not self.get("env"): + self.set("env", self._environment) + + self.do_discover() + self.do_provision() + + self.set_ready() +
    + @property + def _environment(self): + return self.ccnd.path + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncat.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncat.html new file mode 100644 index 00000000..f2bbea97 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncat.html @@ -0,0 +1,163 @@ + + + + + + + + nepi.resources.linux.ccn.ccncat — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ccn.ccncat

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.ccn.ccnapplication import LinuxCCNApplication
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxCCNCat(LinuxCCNApplication): + _rtype = "linux::CCNCat" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "Content name for the content to peek", + flags = Flags.Design) + + pipeline = Attribute("pipeline", + "CCNCat pipeline", + flags = Flags.Design) + + cls._register_attribute(content_name) + cls._register_attribute(pipeline) + + def __init__(self, ec, guid): + super(LinuxCCNCat, self).__init__(ec, guid) + self._home = "ccncat-%s" % self.guid + +
    [docs] def do_deploy(self): + if not self.ccnd or self.ccnd.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + command = self.get("command") + if not command: + command = "ccncat %s" % self.get("contentName") + if self.get("pipeline"): + command += " -p %s " % self.get("pipeline") + + self.set("command", command) + + self.info("Deploying command '%s' " % command) + + if not self.get("env"): + self.set("env", self._environment) + + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncontent.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncontent.html new file mode 100644 index 00000000..9d0f2479 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncontent.html @@ -0,0 +1,241 @@ + + + + + + + + nepi.resources.linux.ccn.ccncontent — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ccn.ccncontent

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState, \
    +    ResourceAction
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.resources.linux.ccn.ccnr import LinuxCCNR
    +from nepi.util.timefuncs import tnow
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxCCNContent(LinuxApplication): + _rtype = "linux::CCNContent" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "The name of the content to publish (e.g. ccn:/VIDEO) ", + flags = Flags.Design) + + content = Attribute("content", + "The content to publish. It can be a path to a file or plain text ", + flags = Flags.Design) + + scope = Attribute("scope", + "Use the given scope on the start-write request (if -r specified). " + "scope can be 1 (local), 2 (neighborhood), or 3 (unlimited). " + "Note that a scope of 3 is encoded as the absence of any scope in the interest. ", + type = Types.Integer, + default = 1, + flags = Flags.Design) + + cls._register_attribute(content_name) + cls._register_attribute(content) + cls._register_attribute(scope) + + def __init__(self, ec, guid): + super(LinuxCCNContent, self).__init__(ec, guid) + self._home = "content-%s" % self.guid + + @property +
    [docs] def ccnr(self): + ccnr = self.get_connected(LinuxCCNR.get_rtype()) + if ccnr: return ccnr[0] + return None +
    + @property +
    [docs] def ccnd(self): + if self.ccnr: return self.ccnr.ccnd + return None +
    + @property +
    [docs] def node(self): + if self.ccnr: return self.ccnr.node + return None +
    +
    [docs] def do_deploy(self): + if not self.ccnr or self.ccnr.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + + # ccnr needs to wait until ccnd is deployed and running + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("env"): + self.set("env", self._environment) + + # set content to stdin, so the content will be + # uploaded during provision + self.set("stdin", self.get("content")) + + command = self.get("command") + + self.info("Deploying command '%s' " % command) + + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def upload_start_command(self): + command = self.get("command") + env = self.get("env") + + self.info("Uploading command '%s'" % command) + + # We want to make sure the content is published + # before the experiment starts. + # Run the command as a bash script in the background, + # in the host ( but wait until the command has + # finished to continue ) + env = self.replace_paths(env) + command = self.replace_paths(command) + + (out, err), proc = self.execute_command(command, + env, blocking = True) + + if proc.poll(): + msg = "Failed to execute command" + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
    + @property + def _start_command(self): + command = ["ccnseqwriter"] + command.append("-r %s" % self.get("contentName")) + command.append("-s %d" % self.get("scope")) + command.append("< %s" % os.path.join(self.app_home, 'stdin')) + + command = " ".join(command) + return command + + @property + def _environment(self): + return self.ccnd.path + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnd.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnd.html new file mode 100644 index 00000000..062828ab --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnd.html @@ -0,0 +1,442 @@ + + + + + + + + nepi.resources.linux.ccn.ccnd — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ccn.ccnd

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.resources.linux.node import OSType
    +from nepi.util.timefuncs import tnow, tdiffsec
    +
    +import os
    +
    +# TODO: use ccndlogging to dynamically change the logging level
    +
    +
    +@clsinit_copy
    +
    [docs]class LinuxCCND(LinuxApplication): + _rtype = "linux::CCND" + + @classmethod + def _register_attributes(cls): + debug = Attribute("debug", "Sets the CCND_DEBUG environmental variable. " + " Allowed values are : \n" + " 0 - no messages \n" + " 1 - basic messages (any non-zero value gets these) \n" + " 2 - interest messages \n" + " 4 - content messages \n" + " 8 - matching details \n" + " 16 - interest details \n" + " 32 - gory interest details \n" + " 64 - log occasional human-readable timestamps \n" + " 128 - face registration debugging \n" + " -1 - max logging \n" + " Or apply bitwise OR to these values to get combinations of them", + type = Types.Integer, + flags = Flags.Design) + + port = Attribute("port", "Sets the CCN_LOCAL_PORT environmental variable. " + "Defaults to 9695 ", + flags = Flags.Design) + + sockname = Attribute("sockname", + "Sets the CCN_LOCAL_SCOKNAME environmental variable. " + "Defaults to /tmp/.ccnd.sock", + flags = Flags.Design) + + capacity = Attribute("capacity", + "Sets the CCND_CAP environmental variable. " + "Capacity limit in terms of ContentObjects", + flags = Flags.Design) + + mtu = Attribute("mtu", "Sets the CCND_MTU environmental variable. ", + flags = Flags.Design) + + data_pause = Attribute("dataPauseMicrosec", + "Sets the CCND_DATA_PAUSE_MICROSEC environmental variable. ", + flags = Flags.Design) + + default_stale = Attribute("defaultTimeToStale", + "Sets the CCND_DEFAULT_TIME_TO_STALE environmental variable. ", + flags = Flags.Design) + + max_stale = Attribute("maxTimeToStale", + "Sets the CCND_MAX_TIME_TO_STALE environmental variable. ", + flags = Flags.Design) + + max_rte = Attribute("maxRteMicrosec", + "Sets the CCND_MAX_RTE_MICROSEC environmental variable. ", + flags = Flags.Design) + + keystore = Attribute("keyStoreDirectory", + "Sets the CCND_KEYSTORE_DIRECTORY environmental variable. ", + flags = Flags.Design) + + listen_on = Attribute("listenOn", + "Sets the CCND_LISTEN_ON environmental variable. ", + flags = Flags.Design) + + autoreg = Attribute("autoreg", + "Sets the CCND_AUTOREG environmental variable. ", + flags = Flags.Design) + + prefix = Attribute("prefix", + "Sets the CCND_PREFIX environmental variable. ", + flags = Flags.Design) + + cls._register_attribute(debug) + cls._register_attribute(port) + cls._register_attribute(sockname) + cls._register_attribute(capacity) + cls._register_attribute(mtu) + cls._register_attribute(data_pause) + cls._register_attribute(default_stale) + cls._register_attribute(max_stale) + cls._register_attribute(max_rte) + cls._register_attribute(keystore) + cls._register_attribute(listen_on) + cls._register_attribute(autoreg) + cls._register_attribute(prefix) + + @classmethod + def _register_traces(cls): + log = Trace("log", "CCND log output") + status = Trace("status", "ccndstatus output") + + cls._register_trace(log) + cls._register_trace(status) + + def __init__(self, ec, guid): + super(LinuxCCND, self).__init__(ec, guid) + self._home = "ccnd-%s" % self.guid + self._version = "ccnx" + + @property +
    [docs] def version(self): + return self._version +
    + @property +
    [docs] def path(self): + return "PATH=$PATH:${BIN}/%s/" % self.version +
    +
    [docs] def do_deploy(self): + if not self.node or self.node.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + + # ccnd needs to wait until node is deployed and running + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("depends"): + self.set("depends", self._dependencies) + + if not self.get("sources"): + self.set("sources", self._sources) + + sources = self.get("sources") + source = sources.split(" ")[0] + basename = os.path.basename(source) + self._version = ( basename.strip().replace(".tar.gz", "") + .replace(".tar","") + .replace(".gz","") + .replace(".zip","") ) + + if not self.get("build"): + self.set("build", self._build) + + if not self.get("install"): + self.set("install", self._install) + + if not self.get("env"): + self.set("env", self._environment) + + command = self.get("command") + + self.info("Deploying command '%s' " % command) + + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def upload_start_command(self): + command = self.get("command") + env = self.get("env") + + # We want to make sure the ccnd is running + # before the experiment starts. + # Run the command as a bash script in background, + # in the host ( but wait until the command has + # finished to continue ) + env = self.replace_paths(env) + command = self.replace_paths(command) + + shfile = os.path.join(self.app_home, "start.sh") + self.node.run_and_wait(command, self.run_home, + shfile = shfile, + overwrite = False, + env = env) +
    +
    [docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def do_stop(self): + command = self.get('command') or '' + + if self.state == ResourceState.STARTED: + self.info("Stopping command '%s'" % command) + + command = "ccndstop" + env = self.get("env") + + # replace application specific paths in the command + command = self.replace_paths(command) + env = env and self.replace_paths(env) + + # Upload the command to a file, and execute asynchronously + shfile = os.path.join(self.app_home, "stop.sh") + self.node.run_and_wait(command, self.run_home, + shfile = shfile, + overwrite = False, + env = env, + pidfile = "ccndstop_pidfile", + ecodefile = "ccndstop_exitcode", + stdout = "ccndstop_stdout", + stderr = "ccndstop_stderr") + + self.set_stopped() +
    + @property +
    [docs] def state(self): + # First check if the ccnd has failed + state_check_delay = 0.5 + if self._state == ResourceState.STARTED and \ + tdiffsec(tnow(), self._last_state_check) > state_check_delay: + (out, err), proc = self._ccndstatus() + + retcode = proc.poll() + + if retcode == 1 and err.find("No such file or directory") > -1: + # ccnd is not running (socket not found) + self.set_stopped() + elif retcode: + # other errors ... + msg = " Failed to execute command '%s'" % self.get("command") + self.error(msg, out, err) + self.fail() + + self._last_state_check = tnow() + + return self._state +
    + def _ccndstatus(self): + env = self.get('env') or "" + environ = self.node.format_environment(env, inline = True) + command = environ + " ccndstatus" + command = self.replace_paths(command) + + return self.node.execute(command) + + @property + def _start_command(self): + return "ccndstart" + + @property + def _dependencies(self): + if self.node.use_rpm: + return ( " autoconf openssl-devel expat-devel libpcap-devel " + " ecryptfs-utils-devel libxml2-devel automake gawk " + " gcc gcc-c++ git pcre-devel make ") + elif self.node.use_deb: + return ( " autoconf libssl-dev libexpat-dev libpcap-dev " + " libecryptfs0 libxml2-utils automake gawk gcc g++ " + " git-core pkg-config libpcre3-dev make ") + return "" + + @property + def _sources(self): + return "http://www.ccnx.org/releases/ccnx-0.8.2.tar.gz" + + @property + def _build(self): + sources = self.get("sources").split(" ")[0] + sources = os.path.basename(sources) + + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN}/%(version)s/ccnd && " + " echo 'binaries found, nothing to do' " + " ) || ( " + # If not, untar and build + " ( " + " mkdir -p ${SRC}/%(version)s && " + " tar xf ${SRC}/%(sources)s --strip-components=1 -C ${SRC}/%(version)s " + " ) && " + "cd ${SRC}/%(version)s && " + # Just execute and silence warnings... + " ( ./configure && make ) " + " )") % ({ 'sources': sources, + 'version': self.version + }) + + @property + def _install(self): + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN}/%(version)s/ccnd && " + " echo 'binaries found, nothing to do' " + " ) || ( " + # If not, install + " mkdir -p ${BIN}/%(version)s && " + " mv ${SRC}/%(version)s/bin/* ${BIN}/%(version)s/ " + " )" + ) % ({ 'version': self.version + }) + + @property + def _environment(self): + envs = dict({ + "debug": "CCND_DEBUG", + "port": "CCN_LOCAL_PORT", + "sockname" : "CCN_LOCAL_SOCKNAME", + "capacity" : "CCND_CAP", + "mtu" : "CCND_MTU", + "dataPauseMicrosec" : "CCND_DATA_PAUSE_MICROSEC", + "defaultTimeToStale" : "CCND_DEFAULT_TIME_TO_STALE", + "maxTimeToStale" : "CCND_MAX_TIME_TO_STALE", + "maxRteMicrosec" : "CCND_MAX_RTE_MICROSEC", + "keyStoreDirectory" : "CCND_KEYSTORE_DIRECTORY", + "listenOn" : "CCND_LISTEN_ON", + "autoreg" : "CCND_AUTOREG", + "prefix" : "CCND_PREFIX", + }) + + env = self.path + env += " ".join(map(lambda k: "%s=%s" % (envs.get(k), str(self.get(k))) \ + if self.get(k) else "", envs.keys())) + + return env + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpeek.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpeek.html new file mode 100644 index 00000000..8d52c8fc --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpeek.html @@ -0,0 +1,155 @@ + + + + + + + + nepi.resources.linux.ccn.ccnpeek — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ccn.ccnpeek

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.ccn.ccnapplication import LinuxCCNApplication
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxCCNPeek(LinuxCCNApplication): + _rtype = "linux::CCNPeek" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "Content name for the content to peek", + flags = Flags.Design) + + cls._register_attribute(content_name) + + def __init__(self, ec, guid): + super(LinuxCCNPeek, self).__init__(ec, guid) + self._home = "ccnpeek-%s" % self.guid + +
    [docs] def do_deploy(self): + if not self.ccnd or self.ccnd.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + command = self.get("command") + if not command: + command = "ccnpeek %s" % self.get("contentName") + self.set("command", command) + + self.info("Deploying command '%s' " % command) + + if not self.get("env"): + self.set("env", self._environment) + + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnping.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnping.html new file mode 100644 index 00000000..fcac0904 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnping.html @@ -0,0 +1,186 @@ + + + + + + + + nepi.resources.linux.ccn.ccnping — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ccn.ccnping

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.linux.ccn.ccnpingserver import LinuxCCNPingServer
    +from nepi.util.timefuncs import tnow, tdiffsec
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxCCNPing(LinuxCCNPingServer): + _rtype = "linux::CCNPing" + + @classmethod + def _register_attributes(cls): + interval = Attribute("i", + "Set ping interval in seconds (minimum 0.10 second) ", + type = Types.Integer, + flags = Flags.Design) + + count = Attribute("c", + "Total number of pings", + type = Types.Double, + flags = Flags.Design) + + number = Attribute("n", + "Set the starting number, the number is incremented by 1 after each Interest ", + type = Types.Integer, + flags = Flags.Design) + + prefix = Attribute("prefix", + "Prefix to serve content (e.g. ccnx:/name/prefix)", + flags = Flags.Design) + + cls._register_attribute(interval) + cls._register_attribute(count) + cls._register_attribute(number) + cls._register_attribute(prefix) + + def __init__(self, ec, guid): + super(LinuxCCNPing, self).__init__(ec, guid) + self._home = "ccnping-%s" % self.guid + + @property +
    [docs] def ccnpingserver(self): + ccnpingserver = self.get_connected(LinuxCCNPingServer.get_rtype()) + if ccnpingserver: return ccnpingserver[0] + return None +
    +
    [docs] def do_start(self): + if not self.ccnpingserver or \ + self.ccnpingserver.state < ResourceState.STARTED: + self.debug("---- RESCHEDULING START---- ccnpingserver state %s " % \ + self.ccnpingserver.state ) + self.ec.schedule(self.reschedule_delay, self.start) + else: + super(LinuxCCNPing, self).do_start() +
    + @property + def _start_command(self): + args = [] + args.append("ccnping") + args.append(self.get("prefix")) + if self.get("c"): + args.append("-c %d" % self.get("c")) + if self.get("n"): + args.append("-n %d" % self.get("n")) + if self.get("i"): + args.append("-i %.2f" % self.get("i")) + + command = " ".join(args) + + return command + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpingserver.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpingserver.html new file mode 100644 index 00000000..d3b8af68 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpingserver.html @@ -0,0 +1,225 @@ + + + + + + + + nepi.resources.linux.ccn.ccnpingserver — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ccn.ccnpingserver

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.linux.ccn.ccnapplication import LinuxCCNApplication
    +from nepi.util.timefuncs import tnow, tdiffsec
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxCCNPingServer(LinuxCCNApplication): + _rtype = "linux::CCNPingServer" + + @classmethod + def _register_attributes(cls): + daemon = Attribute("d", + "Run ccnping server as a daemon in background", + type = Types.Bool, + default = False, + flags = Flags.Design) + + freshness = Attribute("x", + "Set FreshnessSeconds", + type = Types.Integer, + flags = Flags.Design) + + prefix = Attribute("prefix", + "Prefix to serve content (e.g. ccnx:/name/prefix)", + flags = Flags.Design) + + cls._register_attribute(daemon) + cls._register_attribute(freshness) + cls._register_attribute(prefix) + + def __init__(self, ec, guid): + super(LinuxCCNPingServer, self).__init__(ec, guid) + self._home = "ccnping-serv-%s" % self.guid + +
    [docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("env"): + self.set("env", self._environment) + + if not self.get("depends"): + self.set("depends", self._dependencies) + + if not self.get("build"): + self.set("build", self._build) + + if not self.get("install"): + self.set("install", self._install) + + super(LinuxCCNPingServer, self).do_deploy() +
    + @property + def _start_command(self): + args = [] + args.append("ccnpingserver") + args.append(self.get("prefix")) + if self.get("d") == True: + args.append("-d") + if self.get("x"): + args.append("-x %d" % self.get("x")) + + command = " ".join(args) + + return command + + @property + def _dependencies(self): + return "git" + + @property + def _build(self): + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN}/ccnping && " + " echo 'binaries found, nothing to do' " + " ) || ( " + # If not, untar and build + " ( " + " git clone git://github.com/NDN-Routing/ccnping ${SRC}/ccnping " + " ) && " + # build + "cd ${SRC}/ccnping && " + " ( " + " ./configure LDFLAGS=-L${SRC}/ccnx-0.7.2/lib CFLAGS=-I${SRC}/ccnx-0.7.2/include " + " --prefix=${BIN}/ccnping && make " + " ) " + " )") + + @property + def _install(self): + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN}/ccnping && " + " echo 'binaries found, nothing to do' " + " ) || ( " + # If not, install + " mkdir -p ${BIN}/ccnping && " + " mv ${SRC}/ccnping/ccnping ${BIN}/ccnping/ && " + " mv ${SRC}/ccnping/ccnpingserver ${BIN}/ccnping/ " + " )" + ) + + @property + def _environment(self): + return "%s:%s" % (self.ccnd.path, "${BIN}/ccnping") + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpoke.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpoke.html new file mode 100644 index 00000000..71ff3d7b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpoke.html @@ -0,0 +1,163 @@ + + + + + + + + nepi.resources.linux.ccn.ccnpoke — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ccn.ccnpoke

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.ccn.ccnapplication import LinuxCCNApplication
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxCCNPoke(LinuxCCNApplication): + _rtype = "linux::CCNPoke" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "Content name for the content to peek", + flags = Flags.Design) + + content = Attribute("content", + "Content to poke (as a text string)", + flags = Flags.Design) + + cls._register_attribute(content_name) + cls._register_attribute(content) + + def __init__(self, ec, guid): + super(LinuxCCNPoke, self).__init__(ec, guid) + self._home = "ccnpoke-%s" % self.guid + +
    [docs] def do_deploy(self): + if not self.ccnd or self.ccnd.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + command = self.get("command") + if not command: + command = "ccnpoke %s" % self.get("contentName") + self.set("command", command) + + self.info("Deploying command '%s' " % command) + + if self.get("content"): + self.set("stdin", self.get("content")) + + if not self.get("env"): + self.set("env", self._environment) + + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnr.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnr.html new file mode 100644 index 00000000..382fc972 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnr.html @@ -0,0 +1,397 @@ + + + + + + + + nepi.resources.linux.ccn.ccnr — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ccn.ccnr

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import clsinit_copy, ResourceState, \
    +    ResourceAction
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.resources.linux.ccn.ccnd import LinuxCCND
    +from nepi.util.timefuncs import tnow
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxCCNR(LinuxApplication): + _rtype = "linux::CCNR" + + @classmethod + def _register_attributes(cls): + max_fanout = Attribute("maxFanout", + "Sets the CCNR_BTREE_MAX_FANOUT environmental variable. ", + flags = Flags.Design) + + max_leaf_entries = Attribute("maxLeafEntries", + "Sets the CCNR_BTREE_MAX_LEAF_ENTRIES environmental variable. ", + flags = Flags.Design) + + max_node_bytes = Attribute("maxNodeBytes", + "Sets the CCNR_BTREE_MAX_NODE_BYTES environmental variable. ", + flags = Flags.Design) + + max_node_pool = Attribute("maxNodePool", + "Sets the CCNR_BTREE_MAX_NODE_POOL environmental variable. ", + flags = Flags.Design) + + content_cache = Attribute("contentCache", + "Sets the CCNR_CONTENT_CACHE environmental variable. ", + flags = Flags.Design) + + debug = Attribute("debug", + "Sets the CCNR_DEBUG environmental variable. " + "Logging level for ccnr. Defaults to WARNING.", + type = Types.Enumerate, + allowed = [ + "NONE", + "SEVERE", + "ERROR", + "WARNING", + "INFO", + "FINE, FINER, FINEST"], + flags = Flags.Design) + + directory = Attribute("directory", + "Sets the CCNR_DIRECTORY environmental variable. ", + flags = Flags.Design) + + global_prefix = Attribute("globalPrefix", + "Sets the CCNR_GLOBAL_PREFIX environmental variable. ", + flags = Flags.Design) + + listen_on = Attribute("listenOn", + "Sets the CCNR_LISTEN_ON environmental variable. ", + flags = Flags.Design) + + min_send_bufsize = Attribute("minSendBufsize", + "Sets the CCNR_MIN_SEND_BUFSIZE environmental variable. ", + flags = Flags.Design) + + proto = Attribute("proto", + "Sets the CCNR_PROTO environmental variable. ", + flags = Flags.Design) + + status_port = Attribute("statusPort", + "Sets the CCNR_STATUS_PORT environmental variable. ", + flags = Flags.Design) + + start_write_scope_limit = Attribute("startWriteScopeLimit", + "Sets the CCNR_START_WRITE_SCOPE_LIMIT environmental variable. ", + flags = Flags.Design) + + ccns_debug = Attribute("ccnsDebug", + "Sets the CCNS_DEBUG environmental variable. ", + flags = Flags.Design) + + ccns_enable = Attribute("ccnsEnable", + "Sets the CCNS_ENABLE environmental variable. ", + flags = Flags.Design) + + ccns_faux_error = Attribute("ccnsFauxError", + "Sets the CCNS_FAUX_ERROR environmental variable. ", + flags = Flags.Design) + + ccns_heartbeat_micros = Attribute("ccnsHeartBeatMicros", + "Sets the CCNS_HEART_BEAT_MICROS environmental variable. ", + flags = Flags.Design) + + ccns_max_compares_busy = Attribute("ccnsMaxComparesBusy", + "Sets the CCNS_MAX_COMPARES_BUSY environmental variable. ", + flags = Flags.Design) + + ccns_max_fetch_busy = Attribute("ccnsMaxFetchBusy", + "Sets the CCNS_MAX_FETCH_BUSY environmental variable. ", + flags = Flags.Design) + + ccns_node_fetch_lifetime = Attribute("ccnsNodeFetchLifetime", + "Sets the CCNS_NODE_FETCH_LIFETIME environmental variable. ", + flags = Flags.Design) + + ccns_note_err = Attribute("ccnsNoteErr", + "Sets the CCNS_NOTE_ERR environmental variable. ", + flags = Flags.Design) + + ccns_repo_store = Attribute("ccnsRepoStore", + "Sets the CCNS_REPO_STORE environmental variable. ", + flags = Flags.Design) + + ccns_root_advise_fresh = Attribute("ccnsRootAdviseFresh", + "Sets the CCNS_ROOT_ADVISE_FRESH environmental variable. ", + flags = Flags.Design) + + ccns_root_advise_lifetime = Attribute("ccnsRootAdviseLifetime", + "Sets the CCNS_ROOT_ADVISE_LIFETIME environmental variable. ", + flags = Flags.Design) + + ccns_stable_enabled = Attribute("ccnsStableEnabled", + "Sets the CCNS_STABLE_ENABLED environmental variable. ", + flags = Flags.Design) + + ccns_sync_scope = Attribute("ccnsSyncScope", + "Sets the CCNS_SYNC_SCOPE environmental variable. ", + flags = Flags.Design) + + repo_file = Attribute("repoFile1", + "The Repository uses $CCNR_DIRECTORY/repoFile1 for " + "persistent storage of CCN Content Objects", + flags = Flags.Design) + + cls._register_attribute(max_fanout) + cls._register_attribute(max_leaf_entries) + cls._register_attribute(max_node_bytes) + cls._register_attribute(max_node_pool) + cls._register_attribute(content_cache) + cls._register_attribute(debug) + cls._register_attribute(directory) + cls._register_attribute(global_prefix) + cls._register_attribute(listen_on) + cls._register_attribute(min_send_bufsize) + cls._register_attribute(proto) + cls._register_attribute(status_port) + cls._register_attribute(start_write_scope_limit) + cls._register_attribute(ccns_debug) + cls._register_attribute(ccns_enable) + cls._register_attribute(ccns_faux_error) + cls._register_attribute(ccns_heartbeat_micros) + cls._register_attribute(ccns_max_compares_busy) + cls._register_attribute(ccns_max_fetch_busy) + cls._register_attribute(ccns_node_fetch_lifetime) + cls._register_attribute(ccns_note_err) + cls._register_attribute(ccns_repo_store) + cls._register_attribute(ccns_root_advise_fresh) + cls._register_attribute(ccns_root_advise_lifetime) + cls._register_attribute(ccns_stable_enabled) + cls._register_attribute(ccns_sync_scope) + cls._register_attribute(repo_file) + + @classmethod + def _register_traces(cls): + log = Trace("log", "CCND log output") + + cls._register_trace(log) + + def __init__(self, ec, guid): + super(LinuxCCNR, self).__init__(ec, guid) + self._home = "ccnr-%s" % self.guid + + @property +
    [docs] def ccnd(self): + ccnd = self.get_connected(LinuxCCND.get_rtype()) + if ccnd: return ccnd[0] + return None +
    + @property +
    [docs] def node(self): + if self.ccnd: return self.ccnd.node + return None +
    +
    [docs] def do_deploy(self): + if not self.ccnd or self.ccnd.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- CCND state %s " % self.ccnd.state ) + + # ccnr needs to wait until ccnd is deployed and running + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("env"): + self.set("env", self._environment) + + command = self.get("command") + + self.info("Deploying command '%s' " % command) + + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def upload_start_command(self): + command = self.get("command") + env = self.get("env") + + if self.get("repoFile1"): + # upload repoFile1 + local_file = self.get("repoFile1") + remote_file = "${RUN_HOME}/repoFile1" + remote_file = self.replace_paths(remote_file) + self.node.upload(local_file, + remote_file, + overwrite = False) + + # We want to make sure the repository is running + # before the experiment starts. + # Run the command as a bash script in background, + # in the host ( but wait until the command has + # finished to continue ) + env = self.replace_paths(env) + command = self.replace_paths(command) + + shfile = os.path.join(self.app_home, "start.sh") + self.node.run_and_wait(command, self.run_home, + shfile = shfile, + overwrite = False, + env = env) +
    +
    [docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
    + @property + def _start_command(self): + return "ccnr &" + + @property + def _environment(self): + envs = dict({ + "maxFanout": "CCNR_BTREE_MAX_FANOUT", + "maxLeafEntries": "CCNR_BTREE_MAX_LEAF_ENTRIES", + "maxNodeBytes": "CCNR_BTREE_MAX_NODE_BYTES", + "maxNodePool": "CCNR_BTREE_MAX_NODE_POOL", + "contentCache": "CCNR_CONTENT_CACHE", + "debug": "CCNR_DEBUG", + "directory": "CCNR_DIRECTORY", + "globalPrefix": "CCNR_GLOBAL_PREFIX", + "listenOn": "CCNR_LISTEN_ON", + "minSendBufsize": "CCNR_MIN_SEND_BUFSIZE", + "proto": "CCNR_PROTO", + "statusPort": "CCNR_STATUS_PORT", + "startWriteScopeLimit": "CCNR_START_WRITE_SCOPE_LIMIT", + "ccnsDebug": "CCNS_DEBUG", + "ccnsEnable": "CCNS_ENABLE", + "ccnsFauxError": "CCNS_FAUX_ERROR", + "ccnsHeartBeatMicros": "CCNS_HEART_BEAT_MICROS", + "ccnsMaxComparesBusy": "CCNS_MAX_COMPARES_BUSY", + "ccnsMaxFetchBusy": "CCNS_MAX_FETCH_BUSY", + "ccnsNodeFetchLifetime": "CCNS_NODE_FETCH_LIFETIME", + "ccnsNoteErr": "CCNS_NOTE_ERR", + "ccnsRepoStore": "CCNS_REPO_STORE", + "ccnsRootAdviseFresh": "CCNS_ROOT_ADVISE_FRESH", + "ccnsRootAdviseLifetime": "CCNS_ROOT_ADVISE_LIFETIME", + "ccnsStableEnabled": "CCNS_STABLE_ENABLED", + "ccnsSyncScope": "CCNS_SYNC_SCOPE", + }) + + env = self.ccnd.path + env += " ".join(map(lambda k: "%s=%s" % (envs.get(k), self.get(k)) \ + if self.get(k) else "", envs.keys())) + + return env + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/fibentry.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/fibentry.html new file mode 100644 index 00000000..240329e9 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/fibentry.html @@ -0,0 +1,367 @@ + + + + + + + + nepi.resources.linux.ccn.fibentry — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ccn.fibentry

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import clsinit_copy, ResourceState, \
    +    ResourceAction
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.resources.linux.ccn.ccnd import LinuxCCND
    +from nepi.util.timefuncs import tnow
    +
    +import os
    +import socket
    +import time
    +
    +
    +# TODO: Add rest of options for ccndc!!!
    +#       Implement ENTRY DELETE!!
    +
    +@clsinit_copy
    +
    [docs]class LinuxFIBEntry(LinuxApplication): + _rtype = "linux::FIBEntry" + + @classmethod + def _register_attributes(cls): + uri = Attribute("uri", + "URI prefix to match and route for this FIB entry", + default = "ccnx:/", + flags = Flags.Design) + + protocol = Attribute("protocol", + "Transport protocol used in network connection to peer " + "for this FIB entry. One of 'udp' or 'tcp'.", + type = Types.Enumerate, + default = "udp", + allowed = ["udp", "tcp"], + flags = Flags.Design) + + host = Attribute("host", + "Peer hostname used in network connection for this FIB entry. ", + flags = Flags.Design) + + port = Attribute("port", + "Peer port address used in network connection to peer " + "for this FIB entry.", + flags = Flags.Design) + + ip = Attribute("ip", + "Peer host public IP used in network connection for this FIB entry. ", + flags = Flags.Design) + + cls._register_attribute(uri) + cls._register_attribute(protocol) + cls._register_attribute(host) + cls._register_attribute(port) + cls._register_attribute(ip) + + @classmethod + def _register_traces(cls): + ping = Trace("ping", "Ping to the peer end") + mtr = Trace("mtr", "Mtr to the peer end") + traceroute = Trace("traceroute", "Tracerout to the peer end") + + cls._register_trace(ping) + cls._register_trace(mtr) + cls._register_trace(traceroute) + + def __init__(self, ec, guid): + super(LinuxFIBEntry, self).__init__(ec, guid) + self._home = "fib-%s" % self.guid + self._ping = None + self._traceroute = None + self._ccnd = None + + @property +
    [docs] def ccnd(self): + if not self._ccnd: + ccnd = self.get_connected(LinuxCCND.get_rtype()) + if ccnd: + self._ccnd = ccnd[0] + + return self._ccnd +
    + @property +
    [docs] def ping(self): + if not self._ping: + from nepi.resources.linux.ping import LinuxPing + ping = self.get_connected(LinuxPing.get_rtype()) + if ping: + self._ping = ping[0] + + return self._ping +
    + @property +
    [docs] def traceroute(self): + if not self._traceroute: + from nepi.resources.linux.traceroute import LinuxTraceroute + traceroute = self.get_connected(LinuxTraceroute.get_rtype()) + if traceroute: + self._traceroute = traceroute[0] + + return self._traceroute +
    + @property +
    [docs] def node(self): + if self.ccnd: return self.ccnd.node + return None +
    +
    [docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + if name == "ping": + if not self.ping: + return None + return self.ec.trace(self.ping.guid, "stdout", attr, block, offset) + + if name == "traceroute": + if not self.traceroute: + return None + return self.ec.trace(self.traceroute.guid, "stdout", attr, block, offset) + + return super(LinuxFIBEntry, self).trace(name, attr, block, offset) +
    +
    [docs] def do_deploy(self): + # Wait until associated ccnd is provisioned + if not self.ccnd or self.ccnd.state < ResourceState.READY: + # ccnr needs to wait until ccnd is deployed and running + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("ip"): + host = self.get("host") + ip = socket.gethostbyname(host) + self.set("ip", ip) + + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("env"): + self.set("env", self._environment) + + command = self.get("command") + + self.info("Deploying command '%s' " % command) + + self.do_discover() + self.do_provision() + self.configure() + + self.set_ready() +
    +
    [docs] def upload_start_command(self): + command = self.get("command") + env = self.get("env") + + # We want to make sure the FIB entries are created + # before the experiment starts. + # Run the command as a bash script in the background, + # in the host ( but wait until the command has + # finished to continue ) + env = env and self.replace_paths(env) + command = self.replace_paths(command) + + # ccndc seems to return exitcode OK even if a (dns) error + # occurred, so we need to account for this case here. + (out, err), proc = self.execute_command(command, + env, blocking = True) + + if proc.poll(): + msg = "Failed to execute command" + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def configure(self): + if self.trace_enabled("ping") and not self.ping: + self.info("Configuring PING trace") + ping = self.ec.register_resource("linux::Ping") + self.ec.set(ping, "printTimestamp", True) + self.ec.set(ping, "target", self.get("host")) + self.ec.set(ping, "earlyStart", True) + self.ec.register_connection(ping, self.node.guid) + self.ec.register_connection(ping, self.guid) + # schedule ping deploy + self.ec.deploy(guids=[ping], group = self.deployment_group) + + if self.trace_enabled("traceroute") and not self.traceroute: + self.info("Configuring TRACEROUTE trace") + traceroute = self.ec.register_resource("linux::Traceroute") + self.ec.set(traceroute, "printTimestamp", True) + self.ec.set(traceroute, "continuous", True) + self.ec.set(traceroute, "target", self.get("host")) + self.ec.set(traceroute, "earlyStart", True) + self.ec.register_connection(traceroute, self.node.guid) + self.ec.register_connection(traceroute, self.guid) + # schedule mtr deploy + self.ec.deploy(guids=[traceroute], group = self.deployment_group) +
    +
    [docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def do_stop(self): + command = self.get('command') + env = self.get('env') + + if self.state == ResourceState.STARTED: + self.info("Stopping command '%s'" % command) + + command = self._stop_command + (out, err), proc = self.execute_command(command, env, + blocking = True) + + self.set_stopped() + + if err: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
    + @property + def _start_command(self): + uri = self.get("uri") or "" + protocol = self.get("protocol") or "" + ip = self.get("ip") or "" + port = self.get("port") or "" + + # add ccnx:/example.com/ udp 224.0.0.204 52428 + return "ccndc add %(uri)s %(protocol)s %(host)s %(port)s" % ({ + "uri" : uri, + "protocol": protocol, + "host": ip, + "port": port + }) + + @property + def _stop_command(self): + uri = self.get("uri") or "" + protocol = self.get("protocol") or "" + ip = self.get("ip") or "" + port = self.get("port") or "" + + # add ccnx:/example.com/ udp 224.0.0.204 52428 + return "ccndc del %(uri)s %(protocol)s %(host)s %(port)s" % ({ + "uri" : uri, + "protocol": protocol, + "host": ip, + "port": port + }) + + @property + def _environment(self): + return self.ccnd.path + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/channel.html new file mode 100644 index 00000000..171732c5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/channel.html @@ -0,0 +1,129 @@ + + + + + + + + nepi.resources.linux.channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +
    +@clsinit_copy
    +
    [docs]class LinuxChannel(ResourceManager): + _rtype = "linux::Channel" + _help = "Represents a wireless channel on a network of Linux hosts" + _platform = "linux" + + def __init__(self, ec, guid): + super(LinuxChannel, self).__init__(ec, guid) + +
    [docs] def log_message(self, msg): + return " guid %d - %s " % (self.guid, msg) +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/debfuncs.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/debfuncs.html new file mode 100644 index 00000000..c1e44985 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/debfuncs.html @@ -0,0 +1,133 @@ + + + + + + + + nepi.resources.linux.debfuncs — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.debfuncs

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +# TODO: Investigate using http://nixos.org/nix/
    +
    +
    [docs]def install_packages_command(os, packages): + if not isinstance(packages, list): + packages = [packages] + + cmd = " && ".join(map(lambda p: + " { dpkg -s %(package)s || sudo -S apt-get -y install %(package)s ; } " % { + 'package': p}, packages)) + + #cmd = { dpkg -s vim || sudo -S apt-get -y install vim ; } && .. + return cmd +
    +
    [docs]def remove_packages_command(os, packages): + if not isinstance(packages, list): + packages = [packages] + + cmd = " && ".join(map(lambda p: + " { dpkg -s %(package)s && sudo -S apt-get -y purge %(package)s ; } " % { + 'package': p}, packages)) + + #cmd = { dpkg -s vim && sudo -S apt-get -y purge vim ; } && .. + return cmd +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/gretunnel.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/gretunnel.html new file mode 100644 index 00000000..563f0b05 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/gretunnel.html @@ -0,0 +1,177 @@ + + + + + + + + nepi.resources.linux.gretunnel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.gretunnel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.tunnel import LinuxTunnel
    +from nepi.util.sshfuncs import ProcStatus
    +from nepi.util.timefuncs import tnow, tdiffsec
    +
    +import re
    +import socket
    +import time
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxGRETunnel(LinuxTunnel): + _rtype = "linux::GRETunnel" + _help = "Constructs a tunnel between two Linux endpoints using a UDP connection " + +
    [docs] def log_message(self, msg): + return " guid %d - GRE tunnel %s - %s - %s " % (self.guid, + self.endpoint1.node.get("hostname"), + self.endpoint2.node.get("hostname"), + msg) +
    +
    [docs] def get_endpoints(self): + """ Returns the list of RM that are endpoints to the tunnel + """ + connected = [] + for guid in self.connections: + rm = self.ec.get_resource(guid) + if hasattr(rm, "gre_connect"): + connected.append(rm) + return connected +
    +
    [docs] def initiate_connection(self, endpoint, remote_endpoint): + # Return the command to execute to initiate the connection to the + # other endpoint + connection_run_home = self.run_home(endpoint) + connection_app_home = self.app_home(endpoint) + data = endpoint.gre_connect(remote_endpoint, + connection_app_home, + connection_run_home) + return data +
    +
    [docs] def establish_connection(self, endpoint, remote_endpoint, data): + pass +
    +
    [docs] def verify_connection(self, endpoint, remote_endpoint): + remote_ip = socket.gethostbyname(remote_endpoint.node.get("hostname")) + + command = "ping -c 4 %s" % remote_ip + (out, err), proc = endpoint.node.execute(command, + blocking = True) + + m = re.search("(\d+)% packet loss", str(out)) + if not m or int(m.groups()[0]) == 100: + msg = " Error establishing GRE Tunnel" + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def terminate_connection(self, endpoint, remote_endpoint): + pass +
    +
    [docs] def check_state_connection(self): + pass +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/interface.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/interface.html new file mode 100644 index 00000000..d1a91d19 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/interface.html @@ -0,0 +1,402 @@ + + + + + + + + nepi.resources.linux.interface — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.interface

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Types, Flags
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.linux.node import LinuxNode
    +from nepi.resources.linux.channel import LinuxChannel
    +
    +import collections
    +import os
    +import random
    +import re
    +import tempfile
    +import time
    +
    +# TODO: 
    +#     - check UP, MTU attributes!
    +#     - clean up code and test!
    +
    +@clsinit_copy
    +
    [docs]class LinuxInterface(ResourceManager): + _rtype = "linux::Interface" + _help = "Controls network devices on Linux hosts through the ifconfig tool" + _platform = "linux" + + @classmethod + def _register_attributes(cls): + ip4 = Attribute("ip4", "IPv4 Address", + flags = Flags.Design) + + ip6 = Attribute("ip6", "IPv6 Address", + flags = Flags.Design) + + mac = Attribute("mac", "MAC Address", + flags = Flags.Design) + + mask4 = Attribute("mask4", "IPv4 network mask", + flags = Flags.Design) + + mask6 = Attribute("mask6", "IPv6 network mask", + type = Types.Integer, + flags = Flags.Design) + + mtu = Attribute("mtu", "Maximum transmition unit for device", + type = Types.Integer) + + devname = Attribute("deviceName", + "Name of the network interface (e.g. eth0, wlan0, etc)", + flags = Flags.Design) + + up = Attribute("up", "Link up", type = Types.Bool) + + tear_down = Attribute("tearDown", "Bash script to be executed before " + \ + "releasing the resource", + flags = Flags.Design) + + cls._register_attribute(ip4) + cls._register_attribute(ip6) + cls._register_attribute(mac) + cls._register_attribute(mask4) + cls._register_attribute(mask6) + cls._register_attribute(mtu) + cls._register_attribute(devname) + cls._register_attribute(up) + cls._register_attribute(tear_down) + + def __init__(self, ec, guid): + super(LinuxInterface, self).__init__(ec, guid) + self._configured = False + + self.add_set_hooks() + +
    [docs] def log_message(self, msg): + return " guid %d - host %s - %s " % (self.guid, + self.node.get("hostname"), msg) +
    + @property +
    [docs] def node(self): + node = self.get_connected(LinuxNode.get_rtype()) + if node: return node[0] + return None +
    + @property +
    [docs] def channel(self): + chan = self.get_connected(LinuxChannel.get_rtype()) + if chan: return chan[0] + return None +
    +
    [docs] def do_discover(self): + devname = self.get("deviceName") + ip4 = self.get("ip4") + ip6 = self.get("ip4") + mac = self.get("mac") + mask4 = self.get("mask4") + mask6 = self.get("mask6") + mtu = self.get("mtu") + + # Get current interfaces information + (out, err), proc = self.node.execute("ifconfig", sudo = True, tty = True) + + if err and proc.poll(): + msg = " Error retrieving interface information " + self.error(msg, out, err) + raise RuntimeError, "%s - %s - %s" % (msg, out, err) + + # Check if an interface is found matching the RM attributes + ifaces = out.split("\n\n") + + for i in ifaces: + m = re.findall("(\w+)\s+Link\s+encap:\w+(\s+HWaddr\s+(([0-9a-fA-F]{2}:?){6}))?(\s+inet\s+addr:((\d+\.?){4}).+Mask:(\d+\.\d+\.\d+\.\d+))?(.+inet6\s+addr:\s+([0-9a-fA-F:.]+)/(\d+))?(.+(UP))?(.+MTU:(\d+))?", i, re.DOTALL) + + m = m[0] + dn = m[0] + mc = m[2] + i4 = m[5] + msk4 = m[7] + i6 = m[9] + msk6 = m[10] + up = True if m[12] else False + mu = m[14] + + self.debug("Found interface %(devname)s with MAC %(mac)s," + "IPv4 %(ipv4)s %(mask4)s IPv6 %(ipv6)s/%(mask6)s %(up)s %(mtu)s" % ({ + 'devname': dn, + 'mac': mc, + 'ipv4': i4, + 'mask4': msk4, + 'ipv6': i6, + 'mask6': msk6, + 'up': up, + 'mtu': mu + }) ) + + # If the user didn't provide information we take the first + # interface that is UP + if not devname and not ip4 and not ip6 and up: + self._configured = True + self.load_configuration(dn, mc, i4, msk4, i6, msk6, mu, up) + break + + # If the user provided ipv4 or ipv6 matching that of an interface + # load the interface info + if (ip4 and ip4 == i4) or (ip6 and ip6 == i6): + self._configured = True + self.load_configuration(dn, mc, i4, msk4, i6, msk6, mu, up) + break + + # If the user provided the device name we load the associated info + if devname and devname == dn: + if ((ip4 and ip4 == i4) and (ipv6 and ip6 == i6)) or \ + not (ip4 or ip6): + self._configured = True + + # If the user gave a different ip than the existing, asume ip + # needs to be changed + i4 = ip4 or i4 + i6 = ip6 or i6 + mu = mtu or mu + + self.load_configuration(dn, mc, i4, msk4, i6, msk6, mu, up) + break + + if not self.get("deviceName"): + msg = "Unable to resolve interface " + self.error(msg) + raise RuntimeError, msg + + super(LinuxInterface, self).do_discover() +
    +
    [docs] def do_provision(self): + devname = self.get("deviceName") + ip4 = self.get("ip4") + ip6 = self.get("ip4") + mac = self.get("mac") + mask4 = self.get("mask4") + mask6 = self.get("mask6") + mtu = self.get("mtu") + + # Must configure interface if configuration is required + if not self._configured: + cmd = "ifconfig %s" % devname + + if ip4 and mask4: + cmd += " %(ip4)s netmask %(mask4)s broadcast %(bcast)s up" % ({ + 'ip4': ip4, + 'mask4': mask4, + 'bcast': bcast}) + if mtu: + cmd += " mtu %d " % mtu + + (out, err), proc = self.node.execute(cmd, sudo = True) + + if err and proc.poll(): + msg = "Error configuring interface with command '%s'" % cmd + self.error(msg, out, err) + raise RuntimeError, "%s - %s - %s" % (msg, out, err) + + if ip6 and mask6: + cmd = "ifconfig %(devname)s inet6 add %(ip6)s/%(mask6)d" % ({ + 'devname': devname, + 'ip6': ip6, + 'mask6': mask6}) + + (out, err), proc = self.node.execute(cmd, sudo = True) + + if err and proc.poll(): + msg = "Error seting ipv6 for interface using command '%s' " % cmd + self.error(msg, out, err) + raise RuntimeError, "%s - %s - %s" % (msg, out, err) + + super(LinuxInterface, self).do_provision() +
    +
    [docs] def do_deploy(self): + # Wait until node is provisioned + node = self.node + chan = self.channel + + if not node or node.state < ResourceState.PROVISIONED: + self.ec.schedule(self.reschedule_delay, self.deploy) + elif not chan or chan.state < ResourceState.READY: + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + # Verify if the interface exists in node. If not, configue + # if yes, load existing configuration + self.do_discover() + self.do_provision() + + super(LinuxInterface, self).do_deploy() +
    +
    [docs] def do_release(self): + tear_down = self.get("tearDown") + if tear_down: + self.execute(tear_down) + + super(LinuxInterface, self).do_release() +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    +
    [docs] def load_configuration(self, devname, mac, ip4, mask4, ip6, mask6, mtu, up): + self.set("deviceName", devname) + self.set("mac", mac) + self.set("ip4", ip4) + self.set("mask4", mask4) + self.set("ip6", ip6) + self.set("mask6", mask6) + + # set the following without validating or triggering hooks + attr = self._attrs["up"] + attr._value = up + attr = self._attrs["mtu"] + attr._value = mtu +
    +
    [docs] def add_set_hooks(self): + attrup = self._attrs["up"] + attrup.set_hook = self.set_hook_up + + attrmtu = self._attrs["mtu"] + attrmtu.set_hook = self.set_hook_mtu +
    +
    [docs] def set_hook_up(self, oldval, newval): + if self.state == ResourceState.NEW or oldval == newval: + return oldval + + # configure interface up + if newval == True: + cmd = "ifup %s" % self.get("deviceName") + elif newval == False: + cmd = "ifdown %s" % self.get("deviceName") + + (out, err), proc = self.node.execute(cmd, sudo = True) + + if err and proc.poll(): + msg = "Error setting interface up/down using command '%s' " % cmd + self.error(msg, err, out) + return oldval + + return newval +
    +
    [docs] def set_hook_mtu(self, oldval, newval): + if self.state == ResourceState.NEW or oldval == newval: + return oldval + + cmd = "ifconfig %s mtu %d" % (self.get("deviceName"), newval) + + (out, err), proc = self.node.execute(cmd, sudo = True) + + if err and proc.poll(): + msg = "Error setting interface MTU using command '%s' " % cmd + self.error(msg, err, out) + return oldval + + return newval +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/mtr.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/mtr.html new file mode 100644 index 00000000..b7ff738e --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/mtr.html @@ -0,0 +1,240 @@ + + + + + + + + nepi.resources.linux.mtr — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.mtr

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState 
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.util.timefuncs import tnow
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxMtr(LinuxApplication): + _rtype = "linux::Mtr" + + @classmethod + def _register_attributes(cls): + report_cycles = Attribute("reportCycles", + "sets mtr --report-cycles (-c) option. Determines the number of " + "pings sent to determine both machines in the networks. Each " + "cycle lasts one sencond.", + flags = Flags.Design) + + no_dns = Attribute("noDns", + "sets mtr --no-dns (-n) option. Forces mtr to display IPs intead of " + "trying to resolve to host names ", + type = Types.Bool, + default = True, + flags = Flags.Design) + + address = Attribute("address", + "sets mtr --address (-a) option. Binds the socket to send outgoing " + "packets to the interface of the specified address, so that any " + "any packets are sent through this interface. ", + flags = Flags.Design) + + interval = Attribute("interval", + "sets mtr --interval (-i) option. Specifies the number of seconds " + "between ICMP ECHO requests. Default value is one second ", + flags = Flags.Design) + + countinuous = Attribute("continuous", + "Run mtr in a while loop", + type = Types.Bool, + default = False, + flags = Flags.Design) + + print_timestamp = Attribute("printTimestamp", + "Print timestamp before running mtr", + type = Types.Bool, + default = False, + flags = Flags.Design) + + target = Attribute("target", + "mtr target host (host that will be pinged)", + flags = Flags.Design) + + early_start = Attribute("earlyStart", + "Start ping as early as deployment. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + cls._register_attribute(report_cycles) + cls._register_attribute(no_dns) + cls._register_attribute(address) + cls._register_attribute(interval) + cls._register_attribute(countinuous) + cls._register_attribute(print_timestamp) + cls._register_attribute(target) + cls._register_attribute(early_start) + + def __init__(self, ec, guid): + super(LinuxMtr, self).__init__(ec, guid) + self._home = "mtr-%s" % self.guid + self._sudo_kill = True + +
    [docs] def upload_start_command(self): + super(LinuxMtr, self).upload_start_command() + + if self.get("earlyStart") == True: + self._run_in_background() +
    +
    [docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("env"): + self.set("env", "PATH=$PATH:/usr/sbin/") + + if not self.get("depends"): + self.set("depends", "mtr") + + super(LinuxMtr, self).do_deploy() +
    +
    [docs] def do_start(self): + if self.get("earlyStart") == True: + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg + else: + super(LinuxMtr, self).do_start() +
    + @property + def _start_command(self): + args = [] + if self.get("continuous") == True: + args.append("while true; do ") + if self.get("printTimestamp") == True: + args.append("""echo "`date +'%Y%m%d%H%M%S'`";""") + args.append("sudo -S mtr --report") + if self.get("reportCycles"): + args.append("-c %s" % self.get("reportCycles")) + if self.get("noDns") == True: + args.append("-n") + if self.get("address"): + args.append("-a %s" % self.get("address")) + args.append(self.get("target")) + if self.get("continuous") == True: + args.append("; done ") + + command = " ".join(args) + + return command + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsclient.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsclient.html new file mode 100644 index 00000000..63d53cc8 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsclient.html @@ -0,0 +1,198 @@ + + + + + + + + nepi.resources.linux.netns.netnsclient — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.netns.netnsclient

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import base64
    +import cPickle
    +import errno
    +import os
    +import socket
    +import time
    +import weakref
    +
    +from optparse import OptionParser, SUPPRESS_HELP
    +
    +from nepi.resources.netns.netnsclient import NetNSClient
    +from nepi.resources.netns.netnsserver import NetNSWrapperMessage
    +
    +
    [docs]class LinuxNetNSClient(NetNSClient): + def __init__(self, emulation): + super(LinuxNetNSClient, self).__init__() + self._emulation = weakref.ref(emulation) + + self._socat_proc = None + + @property +
    [docs] def emulation(self): + return self._emulation() +
    +
    [docs] def send_msg(self, msg_type, *args, **kwargs): + msg = [msg_type, args, kwargs] + + def encode(item): + item = cPickle.dumps(item) + return base64.b64encode(item) + + encoded = "|".join(map(encode, msg)) + + if self.emulation.node.get("hostname") in ['localhost', '127.0.0.1']: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(self.emulation.remote_socket) + sock.send("%s\n" % encoded) + reply = sock.recv(1024) + sock.close() + else: + command = ( "python -c 'import socket;" + "sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM);" + "sock.connect(\"%(socket_addr)s\");" + "msg = \"%(encoded_message)s\\n\";" + "sock.send(msg);" + "reply = sock.recv(1024);" + "sock.close();" + "print reply'") % { + "encoded_message": encoded, + "socket_addr": self.emulation.remote_socket, + } + + (reply, err), proc = self.emulation.node.execute(command, + with_lock = True) + + if (err and proc.poll()) or reply.strip() == "": + msg = (" Couldn't connect to remote socket %s - REPLY: %s " + "- ERROR: %s ") % ( + self.emulation.remote_socket, reply, err) + self.emulation.error(msg, reply, err) + raise RuntimeError(msg) + + reply = cPickle.loads(base64.b64decode(reply)) + + return reply +
    +
    [docs] def create(self, *args, **kwargs): + return self.send_msg(NetNSWrapperMessage.CREATE, *args, **kwargs) +
    +
    [docs] def invoke(self, *args, **kwargs): + return self.send_msg(NetNSWrapperMessage.INVOKE, *args, **kwargs) +
    +
    [docs] def set(self, *args, **kwargs): + return self.send_msg(NetNSWrapperMessage.SET, *args, **kwargs) +
    +
    [docs] def get(self, *args, **kwargs): + return self.send_msg(NetNSWrapperMessage.GET, *args, **kwargs) +
    +
    [docs] def flush(self, *args, **kwargs): + return self.send_msg(NetNSWrapperMessage.FLUSH, *args, **kwargs) +
    +
    [docs] def shutdown(self, *args, **kwargs): + try: + return self.send_msg(NetNSWrapperMessage.SHUTDOWN, *args, **kwargs) + except: + pass + + return None +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsemulation.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsemulation.html new file mode 100644 index 00000000..1b3771eb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsemulation.html @@ -0,0 +1,473 @@ + + + + + + + + nepi.resources.linux.netns.netnsemulation — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.netns.netnsemulation

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.util.timefuncs import tnow, tdiffsec
    +from nepi.resources.netns.netnsemulation import NetNSEmulation
    +from nepi.resources.linux.netns.netnsclient import LinuxNetNSClient
    +
    +import os
    +import time
    +import threading
    +
    +@clsinit_copy
    +
    [docs]class LinuxNetNSEmulation(LinuxApplication, NetNSEmulation): + _rtype = "linux::netns::Emulation" + + @classmethod + def _register_attributes(cls): + verbose = Attribute("verbose", + "True to output debugging info for the client-server communication", + type = Types.Bool, + flags = Flags.Design) + + enable_dump = Attribute("enableDump", + "Enable dumping the remote executed commands to a script " + "in order to later reproduce and debug the experiment", + type = Types.Bool, + default = False, + flags = Flags.Design) + + version = Attribute("version", + "Version of netns to install from nsam repo", + default = "netns-dev", + flags = Flags.Design) + + cls._register_attribute(enable_dump) + cls._register_attribute(verbose) + cls._register_attribute(version) + + def __init__(self, ec, guid): + LinuxApplication.__init__(self, ec, guid) + NetNSEmulation.__init__(self) + + self._client = None + self._home = "netns-emu-%s" % self.guid + self._socket_name = "netns-%s.sock" % os.urandom(4).encode('hex') + + @property +
    [docs] def socket_name(self): + return self._socket_name +
    + @property +
    [docs] def remote_socket(self): + return os.path.join(self.run_home, self.socket_name) +
    +
    [docs] def upload_sources(self): + self.node.mkdir(os.path.join(self.node.src_dir, "netnswrapper")) + + # upload wrapper python script + wrapper = os.path.join(os.path.dirname(__file__), "..", "..", "netns", + "netnswrapper.py") + + self.node.upload(wrapper, + os.path.join(self.node.src_dir, "netnswrapper", "netnswrapper.py"), + overwrite = False) + + # upload wrapper debug python script + wrapper_debug = os.path.join(os.path.dirname(__file__), "..", "..", "netns", + "netnswrapper_debug.py") + + self.node.upload(wrapper_debug, + os.path.join(self.node.src_dir, "netnswrapper", "netnswrapper_debug.py"), + overwrite = False) + + # upload server python script + server = os.path.join(os.path.dirname(__file__), "..", "..", "netns", + "netnsserver.py") + + self.node.upload(server, + os.path.join(self.node.src_dir, "netnswrapper", "netnsserver.py"), + overwrite = False) + + # Upload user defined sources + self.node.mkdir(os.path.join(self.node.src_dir, "netns")) + src_dir = os.path.join(self.node.src_dir, "netns") + + super(LinuxNetNSEmulation, self).upload_sources(src_dir = src_dir) +
    +
    [docs] def upload_extra_sources(self, sources = None, src_dir = None): + return super(LinuxNetNSEmulation, self).upload_sources( + sources = sources, + src_dir = src_dir) +
    +
    [docs] def upload_start_command(self): + command = self.get("command") + env = self.get("env") + + # We want to make sure the emulator is running + # before the experiment starts. + # Run the command as a bash script in background, + # in the host ( but wait until the command has + # finished to continue ) + env = self.replace_paths(env) + command = self.replace_paths(command) + + shfile = os.path.join(self.app_home, "start.sh") + self.node.upload_command(command, + shfile = shfile, + env = env, + overwrite = True) + + # Run the wrapper + self._run_in_background() + + # Wait until the remote socket is created + self.wait_remote_socket() +
    +
    [docs] def do_deploy(self): + if not self.node or self.node.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + + # ccnd needs to wait until node is deployed and running + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("depends"): + self.set("depends", self._dependencies) + + if self.get("sources"): + sources = self.get("sources") + source = sources.split(" ")[0] + basename = os.path.basename(source) + version = ( basename.strip().replace(".tar.gz", "") + .replace(".tar","") + .replace(".gz","") + .replace(".zip","") ) + + self.set("version", version) + self.set("sources", source) + + if not self.get("build"): + self.set("build", self._build) + + if not self.get("env"): + self.set("env", self._environment) + + self.do_discover() + self.do_provision() + + # Create client + self._client = LinuxNetNSClient(self) + + self.set_ready() +
    +
    [docs] def do_start(self): + """ Starts execution execution + + """ + self.info("Starting") + + if self.state == ResourceState.READY: + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def do_stop(self): + """ Stops simulation execution + + """ + if self.state == ResourceState.STARTED: + self.set_stopped() +
    +
    [docs] def do_release(self): + self.info("Releasing resource") + + tear_down = self.get("tearDown") + if tear_down: + self.node.execute(tear_down) + + self.do_stop() + self._client.shutdown() + LinuxApplication.do_stop(self) + + super(LinuxApplication, self).do_release() +
    + @property + def _start_command(self): + command = [] + + #command.append("sudo") + command.append("PYTHONPATH=$PYTHONPATH:${SRC}/netnswrapper/") + command.append("python ${SRC}/netnswrapper/netnsserver.py -S %s" % \ + os.path.basename(self.remote_socket) ) + + if self.get("enableDump"): + command.append("-D") + + if self.get("verbose"): + command.append("-v") + + command = " ".join(command) + return command + + @property + def _dependencies(self): + if self.node.use_rpm: + return (" python python-devel mercurial unzip bridge-utils iproute") + elif self.node.use_deb: + return (" python python-dev mercurial unzip bridge-utils iproute") + return "" + + @property +
    [docs] def netns_repo(self): + return "http://nepi.inria.fr/code/netns" +
    + @property +
    [docs] def netns_version(self): + version = self.get("version") + return version or "dev" +
    + @property +
    [docs] def python_unshare_repo(self): + return "http://nepi.inria.fr/code/python-unshare" +
    + @property +
    [docs] def python_unshare_version(self): + return "dev" +
    + @property +
    [docs] def python_passfd_repo(self): + return "http://nepi.inria.fr/code/python-passfd" +
    + @property +
    [docs] def python_passfd_version(self): + return "dev" +
    + @property +
    [docs] def netns_src(self): + location = "${SRC}/netns/%(version)s" \ + % { + "version": self.netns_version, + } + + return location +
    + @property +
    [docs] def python_unshare_src(self): + location = "${SRC}/python_unshare/%(version)s" \ + % { + "version": self.python_unshare_version, + } + + return location +
    + @property +
    [docs] def python_passfd_src(self): + location = "${SRC}/python_passfd/%(version)s" \ + % { + "version": self.python_passfd_version, + } + + return location +
    +
    [docs] def clone_command(self, name, repo, src): + clone_cmd = ( + # Test if alredy cloned + " ( " + " ( " + " ( test -d %(src)s ) " + " && echo '%(name)s binaries found, nothing to do'" + " ) " + " ) " + " || " + # clone source code + " ( " + " mkdir -p %(src)s && " + " hg clone %(repo)s %(src)s" + " ) " + ) % { + "repo": repo, + "src": src, + "name": name, + } + + return clone_cmd +
    + @property + def _build(self): + netns_clone = self.clone_command("netns", self.netns_repo, + self.netns_src) + python_unshare_clone = self.clone_command("python_unshare", + self.python_unshare_repo, self.python_unshare_src) + python_passfd_clone = self.clone_command("python_passfd", + self.python_passfd_repo, self.python_passfd_src) + + build_cmd = ( + # Netns installation + "( %(netns_clone)s )" + " && " + "( %(python_unshare_clone)s )" + " && " + "( %(python_passfd_clone)s )" + ) % { + "netns_clone": netns_clone, + "python_unshare_clone": python_unshare_clone, + "python_passfd_clone": python_passfd_clone, + } + + return build_cmd + + @property + def _environment(self): + env = [] + env.append("PYTHONPATH=$PYTHONPAH:%(netns_src)s/src/:%(python_unshare_src)s/src:%(python_passfd_src)s/src}" % { + "netns_src": self.netns_src, + "python_unshare_src": self.python_unshare_src, + "python_passfd_src": self.python_passfd_src, + }) + + return " ".join(env) + +
    [docs] def replace_paths(self, command): + """ + Replace all special path tags with shell-escaped actual paths. + """ + return ( command + .replace("${USR}", self.node.usr_dir) + .replace("${LIB}", self.node.lib_dir) + .replace("${BIN}", self.node.bin_dir) + .replace("${SRC}", self.node.src_dir) + .replace("${SHARE}", self.node.share_dir) + .replace("${EXP}", self.node.exp_dir) + .replace("${EXP_HOME}", self.node.exp_home) + .replace("${APP_HOME}", self.app_home) + .replace("${RUN_HOME}", self.run_home) + .replace("${NODE_HOME}", self.node.node_home) + .replace("${HOME}", self.node.home_dir) + ) +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    +
    [docs] def wait_remote_socket(self): + """ Waits until the remote socket is created + """ + command = " [ -e %s ] && echo 'DONE' " % self.remote_socket + + for i in xrange(200): + (out, err), proc = self.node.execute(command, retry = 1, + with_lock = True) + + if out.find("DONE") > -1: + break + else: + raise RuntimeError("Remote socket not found at %s" % \ + self.remote_socket) + +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/node.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/node.html new file mode 100644 index 00000000..84bc1c1b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/node.html @@ -0,0 +1,1216 @@ + + + + + + + + nepi.resources.linux.node — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.node

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.linux import rpmfuncs, debfuncs 
    +from nepi.util import sshfuncs, execfuncs
    +from nepi.util.sshfuncs import ProcStatus
    +
    +import collections
    +import os
    +import random
    +import re
    +import tempfile
    +import time
    +import threading
    +import traceback
    +
    +# TODO: Unify delays!!
    +# TODO: Validate outcome of uploads!! 
    +
    +
    [docs]class ExitCode: + """ + Error codes that the rexitcode function can return if unable to + check the exit code of a spawned process + """ + FILENOTFOUND = -1 + CORRUPTFILE = -2 + ERROR = -3 + OK = 0 +
    +
    [docs]class OSType: + """ + Supported flavors of Linux OS + """ + DEBIAN = 1 + UBUNTU = 1 << 1 + FEDORA = 1 << 2 + FEDORA_8 = 1 << 3 | FEDORA + FEDORA_12 = 1 << 4 | FEDORA + FEDORA_14 = 1 << 5 | FEDORA +
    +@clsinit_copy +
    [docs]class LinuxNode(ResourceManager): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + .. note:: + + There are different ways in which commands can be executed using the + LinuxNode interface (i.e. 'execute' - blocking and non blocking, 'run', + 'run_and_wait'). + + Brief explanation: + + * 'execute' (blocking mode) : + + HOW IT WORKS: 'execute', forks a process and run the + command, synchronously, attached to the terminal, in + foreground. + The execute method will block until the command returns + the result on 'out', 'err' (so until it finishes executing). + + USAGE: short-lived commands that must be executed attached + to a terminal and in foreground, for which it IS necessary + to block until the command has finished (e.g. if you want + to run 'ls' or 'cat'). + + * 'execute' (NON blocking mode - blocking = False) : + + HOW IT WORKS: Same as before, except that execute method + will return immediately (even if command still running). + + USAGE: long-lived commands that must be executed attached + to a terminal and in foreground, but for which it is not + necessary to block until the command has finished. (e.g. + start an application using X11 forwarding) + + * 'run' : + + HOW IT WORKS: Connects to the host ( using SSH if remote) + and launches the command in background, detached from any + terminal (daemonized), and returns. The command continues to + run remotely, but since it is detached from the terminal, + its pipes (stdin, stdout, stderr) can't be redirected to the + console (as normal non detached processes would), and so they + are explicitly redirected to files. The pidfile is created as + part of the process of launching the command. The pidfile + holds the pid and ppid of the process forked in background, + so later on it is possible to check whether the command is still + running. + + USAGE: long-lived commands that can run detached in background, + for which it is NOT necessary to block (wait) until the command + has finished. (e.g. start an application that is not using X11 + forwarding. It can run detached and remotely in background) + + * 'run_and_wait' : + + HOW IT WORKS: Similar to 'run' except that it 'blocks' until + the command has finished execution. It also checks whether + errors occurred during runtime by reading the exitcode file, + which contains the exit code of the command that was run + (checking stderr only is not always reliable since many + commands throw debugging info to stderr and the only way to + automatically know whether an error really happened is to + check the process exit code). + + Another difference with respect to 'run', is that instead + of directly executing the command as a bash command line, + it uploads the command to a bash script and runs the script. + This allows to use the bash script to debug errors, since + it remains at the remote host and can be run manually to + reproduce the error. + + USAGE: medium-lived commands that can run detached in + background, for which it IS necessary to block (wait) until + the command has finished. (e.g. Package installation, + source compilation, file download, etc) + + """ + _rtype = "linux::Node" + _help = "Controls Linux host machines ( either localhost or a host " \ + "that can be accessed using a SSH key)" + _platform = "linux" + + @classmethod + def _register_attributes(cls): + hostname = Attribute("hostname", "Hostname of the machine", + flags = Flags.Design) + + username = Attribute("username", "Local account username", + flags = Flags.Credential) + + port = Attribute("port", "SSH port", flags = Flags.Design) + + home = Attribute("home", + "Experiment home directory to store all experiment related files", + flags = Flags.Design) + + identity = Attribute("identity", "SSH identity file", + flags = Flags.Credential) + + server_key = Attribute("serverKey", "Server public key", + flags = Flags.Design) + + clean_home = Attribute("cleanHome", "Remove all nepi files and directories " + " from node home folder before starting experiment", + type = Types.Bool, + default = False, + flags = Flags.Design) + + clean_experiment = Attribute("cleanExperiment", "Remove all files and directories " + " from a previous same experiment, before the new experiment starts", + type = Types.Bool, + default = False, + flags = Flags.Design) + + clean_processes = Attribute("cleanProcesses", + "Kill all running processes before starting experiment", + type = Types.Bool, + default = False, + flags = Flags.Design) + + tear_down = Attribute("tearDown", "Bash script to be executed before " + \ + "releasing the resource", + flags = Flags.Design) + + gateway_user = Attribute("gatewayUser", "Gateway account username", + flags = Flags.Design) + + gateway = Attribute("gateway", "Hostname of the gateway machine", + flags = Flags.Design) + + ip = Attribute("ip", "Linux host public IP address. " + "Must not be modified by the user unless hostname is 'localhost'", + flags = Flags.Design) + + cls._register_attribute(hostname) + cls._register_attribute(username) + cls._register_attribute(port) + cls._register_attribute(home) + cls._register_attribute(identity) + cls._register_attribute(server_key) + cls._register_attribute(clean_home) + cls._register_attribute(clean_experiment) + cls._register_attribute(clean_processes) + cls._register_attribute(tear_down) + cls._register_attribute(gateway_user) + cls._register_attribute(gateway) + cls._register_attribute(ip) + + def __init__(self, ec, guid): + super(LinuxNode, self).__init__(ec, guid) + self._os = None + # home directory at Linux host + self._home_dir = "" + + # lock to prevent concurrent applications on the same node, + # to execute commands at the same time. There are potential + # concurrency issues when using SSH to a same host from + # multiple threads. There are also possible operational + # issues, e.g. an application querying the existence + # of a file or folder prior to its creation, and another + # application creating the same file or folder in between. + self._node_lock = threading.Lock() + +
    [docs] def log_message(self, msg): + return " guid %d - host %s - %s " % (self.guid, + self.get("hostname"), msg) +
    + @property +
    [docs] def home_dir(self): + home = self.get("home") or "" + if not home.startswith("/"): + home = os.path.join(self._home_dir, home) + return home +
    + @property +
    [docs] def nepi_home(self): + return os.path.join(self.home_dir, ".nepi") +
    + @property +
    [docs] def usr_dir(self): + return os.path.join(self.nepi_home, "nepi-usr") +
    + @property +
    [docs] def lib_dir(self): + return os.path.join(self.usr_dir, "lib") +
    + @property +
    [docs] def bin_dir(self): + return os.path.join(self.usr_dir, "bin") +
    + @property +
    [docs] def src_dir(self): + return os.path.join(self.usr_dir, "src") +
    + @property +
    [docs] def share_dir(self): + return os.path.join(self.usr_dir, "share") +
    + @property +
    [docs] def exp_dir(self): + return os.path.join(self.nepi_home, "nepi-exp") +
    + @property +
    [docs] def exp_home(self): + return os.path.join(self.exp_dir, self.ec.exp_id) +
    + @property +
    [docs] def node_home(self): + return os.path.join(self.exp_home, "node-%d" % self.guid) +
    + @property +
    [docs] def run_home(self): + return os.path.join(self.node_home, self.ec.run_id) +
    + @property +
    [docs] def os(self): + if self._os: + return self._os + + if not self.localhost and not self.get("username"): + msg = "Can't resolve OS, insufficient data " + self.error(msg) + raise RuntimeError, msg + + out = self.get_os() + + if out.find("Debian") == 0: + self._os = OSType.DEBIAN + elif out.find("Ubuntu") ==0: + self._os = OSType.UBUNTU + elif out.find("Fedora release") == 0: + self._os = OSType.FEDORA + if out.find("Fedora release 8") == 0: + self._os = OSType.FEDORA_8 + elif out.find("Fedora release 12") == 0: + self._os = OSType.FEDORA_12 + elif out.find("Fedora release 14") == 0: + self._os = OSType.FEDORA_14 + else: + msg = "Unsupported OS" + self.error(msg, out) + raise RuntimeError, "%s - %s " %( msg, out ) + + return self._os +
    +
    [docs] def get_os(self): + # The underlying SSH layer will sometimes return an empty + # output (even if the command was executed without errors). + # To work arround this, repeat the operation N times or + # until the result is not empty string + out = "" + try: + (out, err), proc = self.execute("cat /etc/issue", + with_lock = True, + blocking = True) + except: + trace = traceback.format_exc() + msg = "Error detecting OS: %s " % trace + self.error(msg, out, err) + + return out +
    + @property +
    [docs] def use_deb(self): + return (self.os & (OSType.DEBIAN|OSType.UBUNTU)) +
    + @property +
    [docs] def use_rpm(self): + return (self.os & OSType.FEDORA) +
    + @property +
    [docs] def localhost(self): + return self.get("hostname") in ['localhost', '127.0.0.1', '::1'] +
    +
    [docs] def do_provision(self): + # check if host is alive + if not self.is_alive(): + msg = "Deploy failed. Unresponsive node %s" % self.get("hostname") + self.error(msg) + raise RuntimeError, msg + + self.find_home() + + if self.get("cleanProcesses"): + self.clean_processes() + + if self.get("cleanHome"): + self.clean_home() + + if self.get("cleanExperiment"): + self.clean_experiment() + + # Create shared directory structure and node home directory + paths = [self.lib_dir, + self.bin_dir, + self.src_dir, + self.share_dir, + self.node_home] + + self.mkdir(paths) + + # Get Public IP address if possible + if not self.get("ip"): + try: + ip = sshfuncs.gethostbyname(self.get("hostname")) + self.set("ip", ip) + except: + if self.get("gateway") is None: + msg = "Local DNS can not resolve hostname %s" % self.get("hostname") + self.error(msg) + + super(LinuxNode, self).do_provision() +
    +
    [docs] def do_deploy(self): + if self.state == ResourceState.NEW: + self.info("Deploying node") + self.do_discover() + self.do_provision() + + # Node needs to wait until all associated interfaces are + # ready before it can finalize deployment + from nepi.resources.linux.interface import LinuxInterface + ifaces = self.get_connected(LinuxInterface.get_rtype()) + for iface in ifaces: + if iface.state < ResourceState.READY: + self.ec.schedule(self.reschedule_delay, self.deploy) + return + + super(LinuxNode, self).do_deploy() +
    +
    [docs] def do_release(self): + rms = self.get_connected() + for rm in rms: + # Node needs to wait until all associated RMs are released + # before it can be released + if rm.state != ResourceState.RELEASED: + self.ec.schedule(self.reschedule_delay, self.release) + return + + tear_down = self.get("tearDown") + if tear_down: + self.execute(tear_down) + + self.clean_processes() + + super(LinuxNode, self).do_release() +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    +
    [docs] def clean_processes(self): + self.info("Cleaning up processes") + + if self.localhost: + return + + if self.get("username") != 'root': + cmd = ("sudo -S killall tcpdump || /bin/true ; " + + "sudo -S kill -9 $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; " + + "sudo -S killall -u %s || /bin/true ; " % self.get("username")) + else: + if self.state >= ResourceState.READY: + import pickle + pids = pickle.load(open("/tmp/save.proc", "rb")) + pids_temp = dict() + ps_aux = "ps aux |awk '{print $2,$11}'" + (out, err), proc = self.execute(ps_aux) + if len(out) != 0: + for line in out.strip().split("\n"): + parts = line.strip().split(" ") + pids_temp[parts[0]] = parts[1] + kill_pids = set(pids_temp.items()) - set(pids.items()) + kill_pids = ' '.join(dict(kill_pids).keys()) + + cmd = ("killall tcpdump || /bin/true ; " + + "kill $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; " + + "kill %s || /bin/true ; " % kill_pids) + else: + cmd = ("killall tcpdump || /bin/true ; " + + "kill $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; ") + else: + cmd = ("killall tcpdump || /bin/true ; " + + "kill $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; ") + + (out, err), proc = self.execute(cmd, retry = 1, with_lock = True) +
    +
    [docs] def clean_home(self): + """ Cleans all NEPI related folders in the Linux host + """ + self.info("Cleaning up home") + + cmd = "cd %s ; find . -maxdepth 1 -name \.nepi -execdir rm -rf {} + " % ( + self.home_dir ) + + return self.execute(cmd, with_lock = True) +
    +
    [docs] def clean_experiment(self): + """ Cleans all experiment related files in the Linux host. + It preserves NEPI files and folders that have a multi experiment + scope. + """ + self.info("Cleaning up experiment files") + + cmd = "cd %s ; find . -maxdepth 1 -name '%s' -execdir rm -rf {} + " % ( + self.exp_dir, + self.ec.exp_id ) + + return self.execute(cmd, with_lock = True) +
    +
    [docs] def execute(self, command, + sudo = False, + env = None, + tty = False, + forward_x11 = False, + retry = 3, + connect_timeout = 30, + strict_host_checking = False, + persistent = True, + blocking = True, + with_lock = False + ): + """ Notice that this invocation will block until the + execution finishes. If this is not the desired behavior, + use 'run' instead.""" + + if self.localhost: + (out, err), proc = execfuncs.lexec(command, + user = self.get("username"), # still problem with localhost + sudo = sudo, + env = env) + else: + if with_lock: + # If the execute command is blocking, we don't want to keep + # the node lock. This lock is used to avoid race conditions + # when creating the ControlMaster sockets. A more elegant + # solution is needed. + with self._node_lock: + (out, err), proc = sshfuncs.rexec( + command, + host = self.get("hostname"), + user = self.get("username"), + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + sudo = sudo, + identity = self.get("identity"), + server_key = self.get("serverKey"), + env = env, + tty = tty, + forward_x11 = forward_x11, + retry = retry, + connect_timeout = connect_timeout, + persistent = persistent, + blocking = blocking, + strict_host_checking = strict_host_checking + ) + else: + (out, err), proc = sshfuncs.rexec( + command, + host = self.get("hostname"), + user = self.get("username"), + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + sudo = sudo, + identity = self.get("identity"), + server_key = self.get("serverKey"), + env = env, + tty = tty, + forward_x11 = forward_x11, + retry = retry, + connect_timeout = connect_timeout, + persistent = persistent, + blocking = blocking, + strict_host_checking = strict_host_checking + ) + + return (out, err), proc +
    +
    [docs] def run(self, command, home, + create_home = False, + pidfile = 'pidfile', + stdin = None, + stdout = 'stdout', + stderr = 'stderr', + sudo = False, + tty = False, + strict_host_checking = False): + + self.debug("Running command '%s'" % command) + + if self.localhost: + (out, err), proc = execfuncs.lspawn(command, pidfile, + home = home, + create_home = create_home, + stdin = stdin or '/dev/null', + stdout = stdout or '/dev/null', + stderr = stderr or '/dev/null', + sudo = sudo) + else: + with self._node_lock: + (out, err), proc = sshfuncs.rspawn( + command, + pidfile = pidfile, + home = home, + create_home = create_home, + stdin = stdin or '/dev/null', + stdout = stdout or '/dev/null', + stderr = stderr or '/dev/null', + sudo = sudo, + host = self.get("hostname"), + user = self.get("username"), + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + identity = self.get("identity"), + server_key = self.get("serverKey"), + tty = tty, + strict_host_checking = strict_host_checking + ) + + return (out, err), proc +
    +
    [docs] def getpid(self, home, pidfile = "pidfile"): + if self.localhost: + pidtuple = execfuncs.lgetpid(os.path.join(home, pidfile)) + else: + with self._node_lock: + pidtuple = sshfuncs.rgetpid( + os.path.join(home, pidfile), + host = self.get("hostname"), + user = self.get("username"), + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + identity = self.get("identity"), + server_key = self.get("serverKey"), + strict_host_checking = False + ) + + return pidtuple +
    +
    [docs] def status(self, pid, ppid): + if self.localhost: + status = execfuncs.lstatus(pid, ppid) + else: + with self._node_lock: + status = sshfuncs.rstatus( + pid, ppid, + host = self.get("hostname"), + user = self.get("username"), + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + identity = self.get("identity"), + server_key = self.get("serverKey"), + strict_host_checking = False + ) + + return status +
    +
    [docs] def kill(self, pid, ppid, sudo = False): + out = err = "" + proc = None + status = self.status(pid, ppid) + + if status == sshfuncs.ProcStatus.RUNNING: + if self.localhost: + (out, err), proc = execfuncs.lkill(pid, ppid, sudo) + else: + with self._node_lock: + (out, err), proc = sshfuncs.rkill( + pid, ppid, + host = self.get("hostname"), + user = self.get("username"), + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + sudo = sudo, + identity = self.get("identity"), + server_key = self.get("serverKey"), + strict_host_checking = False + ) + + return (out, err), proc +
    +
    [docs] def copy(self, src, dst): + if self.localhost: + (out, err), proc = execfuncs.lcopy(src, dst, + recursive = True) + else: + with self._node_lock: + (out, err), proc = sshfuncs.rcopy( + src, dst, + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + identity = self.get("identity"), + server_key = self.get("serverKey"), + recursive = True, + strict_host_checking = False) + + return (out, err), proc +
    +
    [docs] def upload(self, src, dst, text = False, overwrite = True, + raise_on_error = True): + """ Copy content to destination + + src string with the content to copy. Can be: + - plain text + - a string with the path to a local file + - a string with a semi-colon separeted list of local files + - a string with a local directory + + dst string with destination path on the remote host (remote is + always self.host) + + text src is text input, it must be stored into a temp file before + uploading + """ + # If source is a string input + f = None + if text and not os.path.isfile(src): + # src is text input that should be uploaded as file + # create a temporal file with the content to upload + f = tempfile.NamedTemporaryFile(delete=False) + f.write(src) + f.close() + src = f.name + + # If dst files should not be overwritten, check that the files do not + # exits already + if isinstance(src, str): + src = map(str.strip, src.split(";")) + + if overwrite == False: + src = self.filter_existing_files(src, dst) + if not src: + return ("", ""), None + + if not self.localhost: + # Build destination as <user>@<server>:<path> + dst = "%s@%s:%s" % (self.get("username"), self.get("hostname"), dst) + + ((out, err), proc) = self.copy(src, dst) + + # clean up temp file + if f: + os.remove(f.name) + + if err: + msg = " Failed to upload files - src: %s dst: %s" % (";".join(src), dst) + self.error(msg, out, err) + + msg = "%s out: %s err: %s" % (msg, out, err) + if raise_on_error: + raise RuntimeError, msg + + return ((out, err), proc) +
    +
    [docs] def download(self, src, dst, raise_on_error = True): + if not self.localhost: + # Build destination as <user>@<server>:<path> + src = "%s@%s:%s" % (self.get("username"), self.get("hostname"), src) + + ((out, err), proc) = self.copy(src, dst) + + if err: + msg = " Failed to download files - src: %s dst: %s" % (";".join(src), dst) + self.error(msg, out, err) + + if raise_on_error: + raise RuntimeError, msg + + return ((out, err), proc) +
    +
    [docs] def install_packages_command(self, packages): + command = "" + if self.use_rpm: + command = rpmfuncs.install_packages_command(self.os, packages) + elif self.use_deb: + command = debfuncs.install_packages_command(self.os, packages) + else: + msg = "Error installing packages ( OS not known ) " + self.error(msg, self.os) + raise RuntimeError, msg + + return command +
    +
    [docs] def install_packages(self, packages, home, run_home = None, + raise_on_error = True): + """ Install packages in the Linux host. + + 'home' is the directory to upload the package installation script. + 'run_home' is the directory from where to execute the script. + """ + command = self.install_packages_command(packages) + + run_home = run_home or home + + (out, err), proc = self.run_and_wait(command, run_home, + shfile = os.path.join(home, "instpkg.sh"), + pidfile = "instpkg_pidfile", + ecodefile = "instpkg_exitcode", + stdout = "instpkg_stdout", + stderr = "instpkg_stderr", + overwrite = False, + raise_on_error = raise_on_error) + + return (out, err), proc +
    +
    [docs] def remove_packages(self, packages, home, run_home = None, + raise_on_error = True): + """ Uninstall packages from the Linux host. + + 'home' is the directory to upload the package un-installation script. + 'run_home' is the directory from where to execute the script. + """ + if self.use_rpm: + command = rpmfuncs.remove_packages_command(self.os, packages) + elif self.use_deb: + command = debfuncs.remove_packages_command(self.os, packages) + else: + msg = "Error removing packages ( OS not known ) " + self.error(msg) + raise RuntimeError, msg + + run_home = run_home or home + + (out, err), proc = self.run_and_wait(command, run_home, + shfile = os.path.join(home, "rmpkg.sh"), + pidfile = "rmpkg_pidfile", + ecodefile = "rmpkg_exitcode", + stdout = "rmpkg_stdout", + stderr = "rmpkg_stderr", + overwrite = False, + raise_on_error = raise_on_error) + + return (out, err), proc +
    +
    [docs] def mkdir(self, paths, clean = False): + """ Paths is either a single remote directory path to create, + or a list of directories to create. + """ + if clean: + self.rmdir(paths) + + if isinstance(paths, str): + paths = [paths] + + cmd = " ; ".join(map(lambda path: "mkdir -p %s" % path, paths)) + + return self.execute(cmd, with_lock = True) +
    +
    [docs] def rmdir(self, paths): + """ Paths is either a single remote directory path to delete, + or a list of directories to delete. + """ + + if isinstance(paths, str): + paths = [paths] + + cmd = " ; ".join(map(lambda path: "rm -rf %s" % path, paths)) + + return self.execute(cmd, with_lock = True) +
    +
    [docs] def run_and_wait(self, command, home, + shfile="cmd.sh", + env=None, + overwrite=True, + wait_run=True, + pidfile="pidfile", + ecodefile="exitcode", + stdin=None, + stdout="stdout", + stderr="stderr", + sudo=False, + tty=False, + raise_on_error=True): + """ + Uploads the 'command' to a bash script in the host. + Then runs the script detached in background in the host, and + busy-waites until the script finishes executing. + """ + + if not shfile.startswith("/"): + shfile = os.path.join(home, shfile) + + self.upload_command(command, + shfile = shfile, + ecodefile = ecodefile, + env = env, + overwrite = overwrite) + + command = "bash %s" % shfile + # run command in background in remote host + (out, err), proc = self.run(command, home, + pidfile = pidfile, + stdin = stdin, + stdout = stdout, + stderr = stderr, + sudo = sudo, + tty = tty) + + # check no errors occurred + if proc.poll(): + msg = " Failed to run command '%s' " % command + self.error(msg, out, err) + if raise_on_error: + raise RuntimeError, msg + + # Wait for pid file to be generated + pid, ppid = self.wait_pid( + home = home, + pidfile = pidfile, + raise_on_error = raise_on_error) + + if wait_run: + # wait until command finishes to execute + self.wait_run(pid, ppid) + + (eout, err), proc = self.check_errors(home, + ecodefile = ecodefile, + stderr = stderr) + + # Out is what was written in the stderr file + if err: + msg = " Failed to run command '%s' " % command + self.error(msg, eout, err) + + if raise_on_error: + raise RuntimeError, msg + + (out, oerr), proc = self.check_output(home, stdout) + + return (out, err), proc +
    +
    [docs] def exitcode(self, home, ecodefile = "exitcode"): + """ + Get the exit code of an application. + Returns an integer value with the exit code + """ + (out, err), proc = self.check_output(home, ecodefile) + + # Succeeded to open file, return exit code in the file + if proc.wait() == 0: + try: + return int(out.strip()) + except: + # Error in the content of the file! + return ExitCode.CORRUPTFILE + + # No such file or directory + if proc.returncode == 1: + return ExitCode.FILENOTFOUND + + # Other error from 'cat' + return ExitCode.ERROR +
    +
    [docs] def upload_command(self, command, + shfile="cmd.sh", + ecodefile="exitcode", + overwrite=True, + env=None): + """ Saves the command as a bash script file in the remote host, and + forces to save the exit code of the command execution to the ecodefile + """ + + if not (command.strip().endswith(";") or command.strip().endswith("&")): + command += ";" + + # The exit code of the command will be stored in ecodefile + command = " { %(command)s } ; echo $? > %(ecodefile)s ;" % { + 'command': command, + 'ecodefile': ecodefile, + } + + # Export environment + environ = self.format_environment(env) + + # Add environ to command + command = environ + command + + return self.upload(command, shfile, text=True, overwrite=overwrite) +
    +
    [docs] def format_environment(self, env, inline=False): + """ Formats the environment variables for a command to be executed + either as an inline command + (i.e. export PYTHONPATH=src/..; export LALAL= ..;python script.py) or + as a bash script (i.e. export PYTHONPATH=src/.. \n export LALA=.. \n) + """ + if not env: return "" + + # Remove extra white spaces + env = re.sub(r'\s+', ' ', env.strip()) + + sep = ";" if inline else "\n" + return sep.join(map(lambda e: " export %s" % e, env.split(" "))) + sep +
    +
    [docs] def check_errors(self, home, + ecodefile = "exitcode", + stderr = "stderr"): + """ Checks whether errors occurred while running a command. + It first checks the exit code for the command, and only if the + exit code is an error one it returns the error output. + + """ + proc = None + err = "" + + # get exit code saved in the 'exitcode' file + ecode = self.exitcode(home, ecodefile) + + if ecode in [ ExitCode.CORRUPTFILE, ExitCode.ERROR ]: + err = "Error retrieving exit code status from file %s/%s" % (home, ecodefile) + elif ecode > 0 or ecode == ExitCode.FILENOTFOUND: + # The process returned an error code or didn't exist. + # Check standard error. + (err, eerr), proc = self.check_output(home, stderr) + + # If the stderr file was not found, assume nothing bad happened, + # and just ignore the error. + # (cat returns 1 for error "No such file or directory") + if ecode == ExitCode.FILENOTFOUND and proc.poll() == 1: + err = "" + + return ("", err), proc +
    +
    [docs] def wait_pid(self, home, pidfile = "pidfile", raise_on_error = False): + """ Waits until the pid file for the command is generated, + and returns the pid and ppid of the process """ + pid = ppid = None + delay = 1.0 + + for i in xrange(2): + pidtuple = self.getpid(home = home, pidfile = pidfile) + + if pidtuple: + pid, ppid = pidtuple + break + else: + time.sleep(delay) + delay = delay * 1.5 + else: + msg = " Failed to get pid for pidfile %s/%s " % ( + home, pidfile ) + self.error(msg) + + if raise_on_error: + raise RuntimeError, msg + + return pid, ppid +
    +
    [docs] def wait_run(self, pid, ppid, trial = 0): + """ wait for a remote process to finish execution """ + delay = 1.0 + + while True: + status = self.status(pid, ppid) + + if status is ProcStatus.FINISHED: + break + elif status is not ProcStatus.RUNNING: + delay = delay * 1.5 + time.sleep(delay) + # If it takes more than 20 seconds to start, then + # asume something went wrong + if delay > 20: + break + else: + # The app is running, just wait... + time.sleep(0.5) +
    +
    [docs] def check_output(self, home, filename): + """ Retrives content of file """ + (out, err), proc = self.execute("cat %s" % + os.path.join(home, filename), retry = 1, with_lock = True) + return (out, err), proc +
    +
    [docs] def is_alive(self): + """ Checks if host is responsive + """ + if self.localhost: + return True + + out = err = "" + msg = "Unresponsive host. Wrong answer. " + + # The underlying SSH layer will sometimes return an empty + # output (even if the command was executed without errors). + # To work arround this, repeat the operation N times or + # until the result is not empty string + try: + (out, err), proc = self.execute("echo 'ALIVE'", + blocking = True, + with_lock = True) + + if out.find("ALIVE") > -1: + return True + except: + trace = traceback.format_exc() + msg = "Unresponsive host. Error reaching host: %s " % trace + + self.error(msg, out, err) + return False +
    +
    [docs] def find_home(self): + """ Retrieves host home directory + """ + # The underlying SSH layer will sometimes return an empty + # output (even if the command was executed without errors). + # To work arround this, repeat the operation N times or + # until the result is not empty string + msg = "Impossible to retrieve HOME directory" + try: + (out, err), proc = self.execute("echo ${HOME}", + blocking = True, + with_lock = True) + + if out.strip() != "": + self._home_dir = out.strip() + except: + trace = traceback.format_exc() + msg = "Impossible to retrieve HOME directory %s" % trace + + if not self._home_dir: + self.error(msg) + raise RuntimeError, msg +
    +
    [docs] def filter_existing_files(self, src, dst): + """ Removes files that already exist in the Linux host from src list + """ + # construct a dictionary with { dst: src } + dests = dict(map(lambda s: (os.path.join(dst, os.path.basename(s)), s), src)) \ + if len(src) > 1 else dict({dst: src[0]}) + + command = [] + for d in dests.keys(): + command.append(" [ -f %(dst)s ] && echo '%(dst)s' " % {'dst' : d} ) + + command = ";".join(command) + + (out, err), proc = self.execute(command, retry = 1, with_lock = True) + + for d in dests.keys(): + if out.find(d) > -1: + del dests[d] + + if not dests: + return [] + + return dests.values() +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/nping.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/nping.html new file mode 100644 index 00000000..e4c334ae --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/nping.html @@ -0,0 +1,312 @@ + + + + + + + + nepi.resources.linux.nping — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.nping

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.util.timefuncs import tnow
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxNPing(LinuxApplication): + _rtype = "linux::NPing" + + @classmethod + def _register_attributes(cls): + c = Attribute("c", + "Sets nping -c option. " + "Stop after a given number of rounds. ", + type = Types.Integer, + flags = Flags.Design) + + e = Attribute("e", + "Sets nping -e option. " + "Set the network interface to be used.", + flags = Flags.Design) + + delay = Attribute("delay", + "Sets nping --delay option. " + "Delay between probes ", + flags = Flags.Design) + + rate = Attribute("rate", + "Sets nping --rate option. " + "Send probes at a given rate ", + flags = Flags.Design) + + ttl = Attribute("ttl", + "Sets nping --ttl option. " + "Time To Live. ", + flags = Flags.Design) + + p = Attribute("p", + "Sets nping -p option. " + "Target ports. ", + type = Types.Integer, + flags = Flags.Design) + + tcp = Attribute("tcp", + "Sets nping --tcp option. " + "TCP mode. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + udp = Attribute("udp", + "Sets nping --udp option. " + "UDP mode. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + icmp = Attribute("icmp", + "Sets nping --icmp option. " + "ICMP mode. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + arp = Attribute("arp", + "Sets nping --arp option. " + "ARP mode. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + traceroute = Attribute("traceroute", + "Sets nping --traceroute option. " + "Traceroute mode. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + countinuous = Attribute("continuous", + "Run nping in a while loop", + type = Types.Bool, + default = False, + flags = Flags.Design) + + print_timestamp = Attribute("printTimestamp", + "Print timestamp before running nping", + type = Types.Bool, + default = False, + flags = Flags.Design) + + target = Attribute("target", + "nping target host (host that will be pinged)", + flags = Flags.Design) + + cls._register_attribute(c) + cls._register_attribute(e) + cls._register_attribute(delay) + cls._register_attribute(rate) + cls._register_attribute(ttl) + cls._register_attribute(p) + cls._register_attribute(tcp) + cls._register_attribute(udp) + cls._register_attribute(icmp) + cls._register_attribute(arp) + cls._register_attribute(traceroute) + cls._register_attribute(countinuous) + cls._register_attribute(print_timestamp) + cls._register_attribute(target) + + def __init__(self, ec, guid): + super(LinuxNPing, self).__init__(ec, guid) + self._home = "nping-%s" % self.guid + self._sudo_kill = True + +
    [docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("install"): + self.set("install", self._install) + + if not self.get("env"): + self.set("env", "PATH=$PATH:/usr/sbin/") + + if not self.get("depends"): + self.set("depends", "nmap") + + super(LinuxNPing, self).do_deploy() +
    + @property + def _start_command(self): + args = [] + if self.get("continuous") == True: + args.append("while true; do ") + if self.get("printTimestamp") == True: + args.append("""echo "`date +'%Y%m%d%H%M%S'`";""") + args.append("sudo -S nping ") + if self.get("c"): + args.append("-c %s" % self.get("c")) + if self.get("e"): + args.append("-e %s" % self.get("e")) + if self.get("delay"): + args.append("--delay %s" % self.get("delay")) + if self.get("rate"): + args.append("--rate %s" % self.get("rate")) + if self.get("ttl"): + args.append("--ttl %s" % self.get("ttl")) + if self.get("p"): + args.append("-p %s" % self.get("p")) + if self.get("tcp") == True: + args.append("--tcp") + if self.get("udp") == True: + args.append("--udp") + if self.get("icmp") == True: + args.append("--icmp") + if self.get("arp") == True: + args.append("--arp") + if self.get("traceroute") == True: + args.append("--traceroute") + + args.append(self.get("target")) + + if self.get("continuous") == True: + args.append("; done ") + + command = " ".join(args) + + return command + + @property + def _install(self): + install = "echo 'nothing to do'" + if self.node.use_rpm: + install = ( + " ( " + " ( " + " if [ `uname -m` == 'x86_64' ]; then " + " wget -O nping.rpm http://nmap.org/dist/nping-0.6.25-1.x86_64.rpm ;" + " else wget -O nping.rpm http://nmap.org/dist/nping-0.6.25-1.i386.rpm ;" + " fi " + " )" + " && sudo -S rpm -vhU nping.rpm ) ") + elif self.node.use_deb: + from nepi.resources.linux import debfuncs + install_alien = debfuncs.install_packages_command(self.node.os, "alien gcc") + install = ( + " ( " + " ( " + " if [ `uname -m` == 'x86_64' ]; then " + " wget -O nping.rpm http://nmap.org/dist/nping-0.6.25-1.x86_64.rpm ;" + " else wget -O nping.rpm http://nmap.org/dist/nping-0.6.25-1.i386.rpm ;" + " fi " + " )" + " && %s && sudo alien -i nping.rpm ) " % install_alien) + + return ("( nping --version || %s )" % install) + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccncatdceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccncatdceapplication.html new file mode 100644 index 00000000..600a4233 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccncatdceapplication.html @@ -0,0 +1,153 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.ns3.ccn.ns3ccndceapplication import LinuxNS3CCNDceApplication
    +
    +@clsinit_copy
    +
    [docs]class LinuxNS3DceCCNCat(LinuxNS3CCNDceApplication): + _rtype = "linux::ns3::dce::CCNCat" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "Content name for the requested content object. ", + flags = Flags.Design) + + cls._register_attribute(content_name) + + def _instantiate_object(self): + if not self.get("binary"): + self.set("binary", "ccncat") + + if self.get("contentName"): + self.set("arguments", self.get("contentName")) + + self.set("stdinFile", "") + + super(LinuxNS3DceCCNCat, self)._instantiate_object() + + @property + def _arguments(self): + args = ["-v", "add"] + + if self.get("uri"): + args.append(self.get("uri")) + if self.get("protocol"): + args.append(self.get("protocol")) + if self.get("host"): + args.append(self.get("host")) + if self.get("port"): + args.append(self.get("port")) + if self.get("ip"): + args.append(self.get("ip")) + + return ";".join(args) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccndceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccndceapplication.html new file mode 100644 index 00000000..86012dc2 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccndceapplication.html @@ -0,0 +1,198 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3ccndceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.ccn.ns3ccndceapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.ns3.ns3ccndceapplication import NS3BaseCCNDceApplication
    +
    +@clsinit_copy
    +
    [docs]class LinuxNS3CCNDceApplication(NS3BaseCCNDceApplication): + _rtype = "linux::ns3::dce::CCNApplication" + + @classmethod + def _register_attributes(cls): + sources = Attribute("sources", + "Path to tar.gz file with sources for the application execute in DCE. " + "Sources will be uploaded to ${SRC} and it is the responsibility of " + "the build instructions (in the build attribute) to copy the compiled " + "binaries to the ${BIN_DCE} directory", + flags = Flags.Design) + + build = Attribute("build", + "Instructions to compile sources DCE-compatible way. " + "Note that sources will be uploaded to ${SRC} and the " + "build instructions are responsible for copying the " + "binaries to the ${BIN_DCE} directory. ", + flags = Flags.Design) + + depends = Attribute("depends", + "Space-separated list of packages required to run the application", + flags = Flags.Design) + + files = Attribute("files", + "Semi-colon separated list of 'key=value' pairs to set as " + "DCE files (AddFile). The key should be a path to a local file " + "and the key is the path to be set in DCE for that file" , + flags = Flags.Design) + + stdinfile = Attribute("stdinFile", + "File to set as StdinFile. The value shoudl be either an empty " + "or a path to a local file ", + flags = Flags.Design) + + cls._register_attribute(sources) + cls._register_attribute(build) + cls._register_attribute(depends) + cls._register_attribute(files) + cls._register_attribute(stdinfile) + + def _instantiate_object(self): + command = [] + + # Install package dependencies required to run the binary + depends = self.get("depends") + if depends: + dcmd = self.simulation.install_dependencies(depends = depends) + if dcmd: + command.append(dcmd) + + # Upload sources to generate the binary + sources = self.get("sources") + if sources: + scmd = self.simulation.upload_extra_sources(sources = sources) + if scmd: + command.append(scmd) + + # Upload instructions to build the binary + build = self.get("build") + if build: + bcmd = self.simulation.build(build = build) + if bcmd: + command.append(bcmd) + + # Upload CCN files (e.g. repo) + files = self.get("files") + if files: + upload = [] + for file in map(str.strip, files.split(";")): + localpath, dcepath = files.split("=") + upload.append(localpath) + + sources = ";".join(upload) + fcmd = self.simulation.upload_extra_sources(sources = sources, + src_dir = self.simulation.app_home) + + if fcmd: + command.append(fcmd) + + if command: + deploy_command = ";".join(command) + prefix = "%d_deploy" % self.guid + self.simulation.execute_deploy_command(deploy_command, prefix=prefix) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnddceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnddceapplication.html new file mode 100644 index 00000000..5c91ab0f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnddceapplication.html @@ -0,0 +1,295 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3ccnddceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.ccn.ns3ccnddceapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.ns3.ccn.ns3ccndceapplication import LinuxNS3CCNDceApplication
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxNS3DceCCND(LinuxNS3CCNDceApplication): + _rtype = "linux::ns3::dce::CCND" + + @classmethod + def _register_attributes(cls): + debug = Attribute("debug", "Sets the CCND_DEBUG environmental variable. " + " Allowed values are : \n" + " 0 - no messages \n" + " 1 - basic messages (any non-zero value gets these) \n" + " 2 - interest messages \n" + " 4 - content messages \n" + " 8 - matching details \n" + " 16 - interest details \n" + " 32 - gory interest details \n" + " 64 - log occasional human-readable timestamps \n" + " 128 - face registration debugging \n" + " -1 - max logging \n" + " Or apply bitwise OR to these values to get combinations of them", + type = Types.Integer, + flags = Flags.Design) + + port = Attribute("port", "Sets the CCN_LOCAL_PORT environmental variable. " + "Defaults to 9695 ", + flags = Flags.Design) + + sockname = Attribute("sockname", + "Sets the CCN_LOCAL_SCOKNAME environmental variable. " + "Defaults to /tmp/.ccnd.sock", + flags = Flags.Design) + + capacity = Attribute("capacity", + "Sets the CCND_CAP environmental variable. " + "Capacity limit in terms of ContentObjects", + flags = Flags.Design) + + mtu = Attribute("mtu", "Sets the CCND_MTU environmental variable. ", + flags = Flags.Design) + + data_pause = Attribute("dataPauseMicrosec", + "Sets the CCND_DATA_PAUSE_MICROSEC environmental variable. ", + flags = Flags.Design) + + default_stale = Attribute("defaultTimeToStale", + "Sets the CCND_DEFAULT_TIME_TO_STALE environmental variable. ", + flags = Flags.Design) + + max_stale = Attribute("maxTimeToStale", + "Sets the CCND_MAX_TIME_TO_STALE environmental variable. ", + flags = Flags.Design) + + max_rte = Attribute("maxRteMicrosec", + "Sets the CCND_MAX_RTE_MICROSEC environmental variable. ", + flags = Flags.Design) + + keystore = Attribute("keyStoreDirectory", + "Sets the CCND_KEYSTORE_DIRECTORY environmental variable. ", + flags = Flags.Design) + + listen_on = Attribute("listenOn", + "Sets the CCND_LISTEN_ON environmental variable. ", + flags = Flags.Design) + + autoreg = Attribute("autoreg", + "Sets the CCND_AUTOREG environmental variable. ", + flags = Flags.Design) + + prefix = Attribute("prefix", + "Sets the CCND_PREFIX environmental variable. ", + flags = Flags.Design) + + cls._register_attribute(debug) + cls._register_attribute(port) + cls._register_attribute(sockname) + cls._register_attribute(capacity) + cls._register_attribute(mtu) + cls._register_attribute(data_pause) + cls._register_attribute(default_stale) + cls._register_attribute(max_stale) + cls._register_attribute(max_rte) + cls._register_attribute(keystore) + cls._register_attribute(listen_on) + cls._register_attribute(autoreg) + cls._register_attribute(prefix) + + @property +
    [docs] def version(self): + return self._version +
    + def _instantiate_object(self): + if not self.get("depends"): + self.set("depends", self._dependencies) + + if not self.get("sources"): + self.set("sources", self._sources) + + sources = self.get("sources") + source = sources.split(" ")[0] + basename = os.path.basename(source) + self._version = ( basename.strip().replace(".tar.gz", "") + .replace(".tar","") + .replace(".gz","") + .replace(".zip","") ) + + if not self.get("build"): + self.set("build", self._build) + + if not self.get("binary"): + self.set("binary", "ccnd") + + if not self.get("environment"): + self.set("environment", self._environment) + + super(LinuxNS3DceCCND, self)._instantiate_object() + + @property + def _dependencies(self): + if self.simulation.node.use_rpm: + return ( " autoconf openssl-devel expat-devel libpcap-devel " + " ecryptfs-utils-devel libxml2-devel automake gawk " + " gcc gcc-c++ git pcre-devel make ") + elif self.simulation.node.use_deb: + return ( " autoconf libssl-dev libexpat1-dev libpcap-dev " + " libecryptfs0 libxml2-utils automake gawk gcc g++ " + " git-core pkg-config libpcre3-dev make ") + return "" + + @property + def _sources(self): + #return "http://www.ccnx.org/releases/ccnx-0.8.1.tar.gz" + return "http://www.ccnx.org/releases/ccnx-0.8.2.tar.gz" + + @property + def _build(self): + sources = self.get("sources") + source = sources.split(" ")[0] + tar = os.path.basename(source) + + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN_DCE}/ccnd && " + " echo 'binaries found, nothing to do' " + " ) || " + # If not, untar and build + " ( " + " tar zxf ${SRC}/%(tar)s && " + " cd %(version)s && " + " INSTALL_BASE=${BIN_DCE}/.. ./configure && " + " make MORE_LDLIBS='-pie -rdynamic' && " + " make install && " + " cp ${BIN_DCE}/../bin/ccn* ${BIN_DCE} && " + " cd -" + " )") % ({ 'tar': tar, + 'version': self.version + }) + + @property + def _environment(self): + envs = dict({ + "debug": "CCND_DEBUG", + "port": "CCN_LOCAL_PORT", + "sockname" : "CCN_LOCAL_SOCKNAME", + "capacity" : "CCND_CAP", + "mtu" : "CCND_MTU", + "dataPauseMicrosec" : "CCND_DATA_PAUSE_MICROSEC", + "defaultTimeToStale" : "CCND_DEFAULT_TIME_TO_STALE", + "maxTimeToStale" : "CCND_MAX_TIME_TO_STALE", + "maxRteMicrosec" : "CCND_MAX_RTE_MICROSEC", + "keyStoreDirectory" : "CCND_KEYSTORE_DIRECTORY", + "listenOn" : "CCND_LISTEN_ON", + "autoreg" : "CCND_AUTOREG", + "prefix" : "CCND_PREFIX", + }) + + env = ";".join(map(lambda k: "%s=%s" % (envs.get(k), str(self.get(k))), + [k for k in envs.keys() if self.get(k)])) + + return env +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpeekdceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpeekdceapplication.html new file mode 100644 index 00000000..04d2773c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpeekdceapplication.html @@ -0,0 +1,136 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.ns3.ccn.ns3ccndceapplication import LinuxNS3CCNDceApplication
    +
    +@clsinit_copy
    +
    [docs]class LinuxNS3DceCCNPeek(LinuxNS3CCNDceApplication): + _rtype = "linux::ns3::dce::CCNPeek" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "Content name for the requested content object. ", + flags = Flags.Design) + + cls._register_attribute(content_name) + + def _instantiate_object(self): + if not self.get("binary"): + self.set("binary", "ccnpeek") + + if self.get("contentName"): + self.set("arguments", self.get("contentName")) + + self.set("stdinFile", "") + + super(LinuxNS3DceCCNPeek, self)._instantiate_object() +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpokedceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpokedceapplication.html new file mode 100644 index 00000000..76a1455c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpokedceapplication.html @@ -0,0 +1,155 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.ns3.ccn.ns3ccndceapplication \
    +        import LinuxNS3CCNDceApplication
    +
    +import os
    +import tempfile
    +
    +@clsinit_copy
    +
    [docs]class LinuxNS3DceCCNPoke(LinuxNS3CCNDceApplication): + _rtype = "linux::ns3::dce::CCNPoke" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "Content name for the requested content object. ", + flags = Flags.Design) + content = Attribute("content", + "Content to poke (as a text string). ", + flags = Flags.Design) + + cls._register_attribute(content_name) + cls._register_attribute(content) + + def _instantiate_object(self): + if not self.get("binary"): + self.set("binary", "ccnpoke") + + if self.get("contentName"): + self.set("arguments", self.get("contentName")) + + # Create temporary local file to store content + content = self.get("content") + f = tempfile.NamedTemporaryFile(delete=False) + f.write(content) + f.close() + + localpath = f.name + dcepath = os.path.join("/tmp", os.path.basename(localpath)) + + self.set("environment", "HOME=/root") + self.set("files", "%s=%s" % (localpath, dcepath)) + self.set("stdinFile", dcepath) + + super(LinuxNS3DceCCNPoke, self)._instantiate_object() +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnrdceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnrdceapplication.html new file mode 100644 index 00000000..1d1f7d4b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnrdceapplication.html @@ -0,0 +1,319 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState 
    +from nepi.resources.linux.ns3.ccn.ns3ccndceapplication import LinuxNS3CCNDceApplication
    +
    +@clsinit_copy
    +
    [docs]class LinuxNS3DceCCNR(LinuxNS3CCNDceApplication): + _rtype = "linux::ns3::dce::CCNR" + + @classmethod + def _register_attributes(cls): + max_fanout = Attribute("maxFanout", + "Sets the CCNR_BTREE_MAX_FANOUT environmental variable. ", + flags = Flags.Design) + + max_leaf_entries = Attribute("maxLeafEntries", + "Sets the CCNR_BTREE_MAX_LEAF_ENTRIES environmental variable. ", + flags = Flags.Design) + + max_node_bytes = Attribute("maxNodeBytes", + "Sets the CCNR_BTREE_MAX_NODE_BYTES environmental variable. ", + flags = Flags.Design) + + max_node_pool = Attribute("maxNodePool", + "Sets the CCNR_BTREE_MAX_NODE_POOL environmental variable. ", + flags = Flags.Design) + + content_cache = Attribute("contentCache", + "Sets the CCNR_CONTENT_CACHE environmental variable. ", + flags = Flags.Design) + + debug = Attribute("debug", + "Sets the CCNR_DEBUG environmental variable. " + "Logging level for ccnr. Defaults to WARNING.", + type = Types.Enumerate, + allowed = [ + "NONE", + "SEVERE", + "ERROR", + "WARNING", + "INFO", + "FINE, FINER, FINEST"], + flags = Flags.Design) + + directory = Attribute("directory", + "Sets the CCNR_DIRECTORY environmental variable. ", + flags = Flags.Design) + + global_prefix = Attribute("globalPrefix", + "Sets the CCNR_GLOBAL_PREFIX environmental variable. ", + flags = Flags.Design) + + listen_on = Attribute("listenOn", + "Sets the CCNR_LISTEN_ON environmental variable. ", + flags = Flags.Design) + + min_send_bufsize = Attribute("minSendBufsize", + "Sets the CCNR_MIN_SEND_BUFSIZE environmental variable. ", + flags = Flags.Design) + + proto = Attribute("proto", + "Sets the CCNR_PROTO environmental variable. ", + flags = Flags.Design) + + status_port = Attribute("statusPort", + "Sets the CCNR_STATUS_PORT environmental variable. ", + flags = Flags.Design) + + start_write_scope_limit = Attribute("startWriteScopeLimit", + "Sets the CCNR_START_WRITE_SCOPE_LIMIT environmental variable. ", + flags = Flags.Design) + + ccns_debug = Attribute("ccnsDebug", + "Sets the CCNS_DEBUG environmental variable. ", + flags = Flags.Design) + + ccns_enable = Attribute("ccnsEnable", + "Sets the CCNS_ENABLE environmental variable. ", + flags = Flags.Design) + + ccns_faux_error = Attribute("ccnsFauxError", + "Sets the CCNS_FAUX_ERROR environmental variable. ", + flags = Flags.Design) + + ccns_heartbeat_micros = Attribute("ccnsHeartBeatMicros", + "Sets the CCNS_HEART_BEAT_MICROS environmental variable. ", + flags = Flags.Design) + + ccns_max_compares_busy = Attribute("ccnsMaxComparesBusy", + "Sets the CCNS_MAX_COMPARES_BUSY environmental variable. ", + flags = Flags.Design) + + ccns_max_fetch_busy = Attribute("ccnsMaxFetchBusy", + "Sets the CCNS_MAX_FETCH_BUSY environmental variable. ", + flags = Flags.Design) + + ccns_node_fetch_lifetime = Attribute("ccnsNodeFetchLifetime", + "Sets the CCNS_NODE_FETCH_LIFETIME environmental variable. ", + flags = Flags.Design) + + ccns_note_err = Attribute("ccnsNoteErr", + "Sets the CCNS_NOTE_ERR environmental variable. ", + flags = Flags.Design) + + ccns_repo_store = Attribute("ccnsRepoStore", + "Sets the CCNS_REPO_STORE environmental variable. ", + flags = Flags.Design) + + ccns_root_advise_fresh = Attribute("ccnsRootAdviseFresh", + "Sets the CCNS_ROOT_ADVISE_FRESH environmental variable. ", + flags = Flags.Design) + + ccns_root_advise_lifetime = Attribute("ccnsRootAdviseLifetime", + "Sets the CCNS_ROOT_ADVISE_LIFETIME environmental variable. ", + flags = Flags.Design) + + ccns_stable_enabled = Attribute("ccnsStableEnabled", + "Sets the CCNS_STABLE_ENABLED environmental variable. ", + flags = Flags.Design) + + ccns_sync_scope = Attribute("ccnsSyncScope", + "Sets the CCNS_SYNC_SCOPE environmental variable. ", + flags = Flags.Design) + + repo_file = Attribute("repoFile1", + "The Repository uses $CCNR_DIRECTORY/repoFile1 for " + "persistent storage of CCN Content Objects", + flags = Flags.Design) + + cls._register_attribute(max_fanout) + cls._register_attribute(max_leaf_entries) + cls._register_attribute(max_node_bytes) + cls._register_attribute(max_node_pool) + cls._register_attribute(content_cache) + cls._register_attribute(debug) + cls._register_attribute(directory) + cls._register_attribute(global_prefix) + cls._register_attribute(listen_on) + cls._register_attribute(min_send_bufsize) + cls._register_attribute(proto) + cls._register_attribute(status_port) + cls._register_attribute(start_write_scope_limit) + cls._register_attribute(ccns_debug) + cls._register_attribute(ccns_enable) + cls._register_attribute(ccns_faux_error) + cls._register_attribute(ccns_heartbeat_micros) + cls._register_attribute(ccns_max_compares_busy) + cls._register_attribute(ccns_max_fetch_busy) + cls._register_attribute(ccns_node_fetch_lifetime) + cls._register_attribute(ccns_note_err) + cls._register_attribute(ccns_repo_store) + cls._register_attribute(ccns_root_advise_fresh) + cls._register_attribute(ccns_root_advise_lifetime) + cls._register_attribute(ccns_stable_enabled) + cls._register_attribute(ccns_sync_scope) + cls._register_attribute(repo_file) + + def _instantiate_object(self): + if not self.get("binary"): + self.set("binary", "ccnr") + + if not self.get("environment"): + self.set("environment", self._environment) + + repoFile1 = self.get("repoFile1") + if repoFile1: + env = "CCNR_DIRECTORY=/REPO/" + environment = self.get("environment") + if environment: + env += ";" + environment + self.set("environment", env) + self.set("files", "%s=/REPO/repoFile1" % repoFile1) + + super(LinuxNS3DceCCNR, self)._instantiate_object() + + @property + def _environment(self): + envs = dict({ + "maxFanout": "CCNR_BTREE_MAX_FANOUT", + "maxLeafEntries": "CCNR_BTREE_MAX_LEAF_ENTRIES", + "maxNodeBytes": "CCNR_BTREE_MAX_NODE_BYTES", + "maxNodePool": "CCNR_BTREE_MAX_NODE_POOL", + "contentCache": "CCNR_CONTENT_CACHE", + "debug": "CCNR_DEBUG", + "directory": "CCNR_DIRECTORY", + "globalPrefix": "CCNR_GLOBAL_PREFIX", + "listenOn": "CCNR_LISTEN_ON", + "minSendBufsize": "CCNR_MIN_SEND_BUFSIZE", + "proto": "CCNR_PROTO", + "statusPort": "CCNR_STATUS_PORT", + "startWriteScopeLimit": "CCNR_START_WRITE_SCOPE_LIMIT", + "ccnsDebug": "CCNS_DEBUG", + "ccnsEnable": "CCNS_ENABLE", + "ccnsFauxError": "CCNS_FAUX_ERROR", + "ccnsHeartBeatMicros": "CCNS_HEART_BEAT_MICROS", + "ccnsMaxComparesBusy": "CCNS_MAX_COMPARES_BUSY", + "ccnsMaxFetchBusy": "CCNS_MAX_FETCH_BUSY", + "ccnsNodeFetchLifetime": "CCNS_NODE_FETCH_LIFETIME", + "ccnsNoteErr": "CCNS_NOTE_ERR", + "ccnsRepoStore": "CCNS_REPO_STORE", + "ccnsRootAdviseFresh": "CCNS_ROOT_ADVISE_FRESH", + "ccnsRootAdviseLifetime": "CCNS_ROOT_ADVISE_LIFETIME", + "ccnsStableEnabled": "CCNS_STABLE_ENABLED", + "ccnsSyncScope": "CCNS_SYNC_SCOPE", + }) + + env = ";".join(map(lambda k: "%s=%s" % (envs.get(k), str(self.get(k))), + [k for k in envs.keys() if self.get(k)])) + + return env +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3fibentrydceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3fibentrydceapplication.html new file mode 100644 index 00000000..b9cea6f5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3fibentrydceapplication.html @@ -0,0 +1,196 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.ns3.ccn.ns3ccndceapplication import LinuxNS3CCNDceApplication
    +
    +@clsinit_copy
    +
    [docs]class LinuxNS3DceFIBEntry(LinuxNS3CCNDceApplication): + _rtype = "linux::ns3::dce::FIBEntry" + + @classmethod + def _register_attributes(cls): + uri = Attribute("uri", + "URI prefix to match and route for this FIB entry", + default = "ccnx:/", + flags = Flags.Design) + + protocol = Attribute("protocol", + "Transport protocol used in network connection to peer " + "for this FIB entry. One of 'udp' or 'tcp'.", + type = Types.Enumerate, + default = "udp", + allowed = ["udp", "tcp"], + flags = Flags.Design) + + host = Attribute("host", + "Peer hostname used in network connection for this FIB entry. ", + flags = Flags.Design) + + port = Attribute("port", + "Peer port address used in network connection to peer " + "for this FIB entry.", + flags = Flags.Design) + + ip = Attribute("ip", + "Peer host public IP used in network connection for this FIB entry. ", + flags = Flags.Design) + + home = Attribute("home", "Sets HOME environmental variable. ", + default = "/root", + flags = Flags.Design) + + cls._register_attribute(uri) + cls._register_attribute(protocol) + cls._register_attribute(host) + cls._register_attribute(port) + cls._register_attribute(ip) + cls._register_attribute(home) + + def _instantiate_object(self): + if not self.get("binary"): + self.set("binary", "ccndc") + + if not self.get("arguments"): + self.set("arguments", self._arguments) + + if not self.get("environment"): + self.set("environment", self._environment) + + super(LinuxNS3DceFIBEntry, self)._instantiate_object() + + @property + def _environment(self): + envs = dict({ + "home": "HOME", + }) + + env = ";".join(map(lambda k: "%s=%s" % (envs.get(k), str(self.get(k))), + [k for k in envs.keys() if self.get(k)])) + + return env + + @property + def _arguments(self): + args = ["-v", "add"] + + if self.get("uri"): + args.append(self.get("uri")) + if self.get("protocol"): + args.append(self.get("protocol")) + if self.get("host"): + args.append(self.get("host")) + if self.get("port"): + args.append(self.get("port")) + if self.get("ip"): + args.append(self.get("ip")) + + return ";".join(args) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/fdudptunnel.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/fdudptunnel.html new file mode 100644 index 00000000..bbe45c4d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/fdudptunnel.html @@ -0,0 +1,473 @@ + + + + + + + + nepi.resources.linux.ns3.fdudptunnel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.fdudptunnel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.udptunnel import LinuxUdpTunnel
    +from nepi.util.sshfuncs import ProcStatus
    +from nepi.util.timefuncs import tnow, tdiffsec
    +
    +import base64
    +import os
    +import socket
    +import time
    +
    +@clsinit_copy
    +
    [docs]class LinuxNs3FdUdpTunnel(LinuxUdpTunnel): + _rtype = "linux::ns3::FdUdpTunnel" + _help = "Constructs a tunnel between two Ns-3 FdNetdevices " \ + "located in remote Linux nodes using a UDP connection " + _platform = "linux::ns3" + + @classmethod + def _register_attributes(cls): + cipher = Attribute("cipher", + "Cipher to encript communication. " + "One of PLAIN, AES, Blowfish, DES, DES3. ", + default = None, + allowed = ["PLAIN", "AES", "Blowfish", "DES", "DES3"], + type = Types.Enumerate, + flags = Flags.Design) + + cipher_key = Attribute("cipherKey", + "Specify a symmetric encryption key with which to protect " + "packets across the tunnel. python-crypto must be installed " + "on the system." , + flags = Flags.Design) + + txqueuelen = Attribute("txQueueLen", + "Specifies the interface's transmission queue length. " + "Defaults to 1000. ", + type = Types.Integer, + flags = Flags.Design) + + bwlimit = Attribute("bwLimit", + "Specifies the interface's emulated bandwidth in bytes " + "per second.", + type = Types.Integer, + flags = Flags.Design) + + cls._register_attribute(cipher) + cls._register_attribute(cipher_key) + cls._register_attribute(txqueuelen) + cls._register_attribute(bwlimit) + + def __init__(self, ec, guid): + super(LinuxUdpTunnel, self).__init__(ec, guid) + self._home = "fd-udp-tunnel-%s" % self.guid + self._pids = dict() + self._fd1 = None + self._fd1node = None + self._fd2 = None + self._fd2node = None + self._pi = False + +
    [docs] def log_message(self, msg): + self.get_endpoints() + return " guid %d - %s - %s - %s " % (self.guid, + self.node1.get("hostname"), + self.node2.get("hostname"), + msg) +
    +
    [docs] def get_endpoints(self): + """ Returns the list of RM that are endpoints to the tunnel + """ + if not self._fd2 or not self._fd1: + from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice + devices = self.get_connected(NS3BaseFdNetDevice.get_rtype()) + if not devices or len(devices) != 2: + msg = "linux::ns3::TunTapFdLink must be connected to exactly one FdNetDevice" + self.error(msg) + raise RuntimeError, msg + + self._fd1 = devices[0] + self._fd2 = devices[1] + + simu = self._fd1.simulation + from nepi.resources.linux.node import LinuxNode + nodes = simu.get_connected(LinuxNode.get_rtype()) + self._fd1node = nodes[0] + + simu = self._fd2.simulation + from nepi.resources.linux.node import LinuxNode + nodes = simu.get_connected(LinuxNode.get_rtype()) + self._fd2node = nodes[0] + + if self._fd1node.get("hostname") == \ + self._fd2node.get("hostname"): + msg = "linux::ns3::FdUdpTunnel requires endpoints on different hosts" + self.error(msg) + raise RuntimeError, msg + + return [self._fd1, self._fd2] +
    + @property +
    [docs] def pi(self): + return self._pi +
    + @property +
    [docs] def endpoint1(self): + return self._fd1 +
    + @property +
    [docs] def endpoint2(self): + return self._fd2 +
    + @property +
    [docs] def node1(self): + return self._fd1node +
    + @property +
    [docs] def node2(self): + return self._fd2node +
    +
    [docs] def endpoint_node(self, endpoint): + node = None + if endpoint == self.endpoint1: + node = self.node1 + else: + node = self.node2 + + return node +
    +
    [docs] def app_home(self, endpoint): + node = self.endpoint_node(endpoint) + return os.path.join(node.exp_home, self._home) +
    +
    [docs] def run_home(self, endpoint): + return os.path.join(self.app_home(endpoint), self.ec.run_id) +
    +
    [docs] def upload_sources(self, endpoint): + scripts = [] + + # vif-passfd python script + linux_passfd = os.path.join(os.path.dirname(__file__), + "..", + "scripts", + "fd-udp-connect.py") + + scripts.append(linux_passfd) + + # tunnel creation python script + tunchannel = os.path.join(os.path.dirname(__file__), + "..", + "scripts", + "tunchannel.py") + + scripts.append(tunchannel) + + # Upload scripts + scripts = ";".join(scripts) + + node = self.endpoint_node(endpoint) + node.upload(scripts, + os.path.join(node.src_dir), + overwrite = False) +
    +
    [docs] def endpoint_mkdir(self, endpoint): + node = self.endpoint_node(endpoint) + run_home = self.run_home(endpoint) + node.mkdir(run_home) +
    +
    [docs] def initiate_connection(self, endpoint, remote_endpoint): + cipher = self.get("cipher") + cipher_key = self.get("cipherKey") + bwlimit = self.get("bwLimit") + txqueuelen = self.get("txQueueLen") + + # Upload the tunnel creating script + self.upload_sources(endpoint) + + # Request an address to send the file descriptor to the ns-3 simulation + address = endpoint.recv_fd() + + # execute the tunnel creation script + node = self.endpoint_node(remote_endpoint) + port = self.initiate(endpoint, remote_endpoint, address, cipher, + cipher_key, bwlimit, txqueuelen) + + return port +
    +
    [docs] def establish_connection(self, endpoint, remote_endpoint, port): + self.establish(endpoint, remote_endpoint, port) +
    +
    [docs] def verify_connection(self, endpoint, remote_endpoint): + self.verify(endpoint) +
    +
    [docs] def terminate_connection(self, endpoint, remote_endpoint): + # Nothing to do + return +
    +
    [docs] def check_state_connection(self): + # Make sure the process is still running in background + # No execution errors occurred. Make sure the background + # process with the recorded pid is still running. + + node1 = self.endpoint_node(self.endpoint1) + node2 = self.endpoint_node(self.endpoint2) + run_home1 = self.run_home(self.endpoint1) + run_home2 = self.run_home(self.endpoint1) + (pid1, ppid1) = self._pids[endpoint1] + (pid2, ppid2) = self._pids[endpoint2] + + status1 = node1.status(pid1, ppid1) + status2 = node2.status(pid2, ppid2) + + if status1 == ProcStatus.FINISHED and \ + status2 == ProcStatus.FINISHED: + + # check if execution errors occurred + (out1, err1), proc1 = node1.check_errors(run_home1) + (out2, err2), proc2 = node2.check_errors(run_home2) + + if err1 or err2: + msg = "Error occurred in tunnel" + self.error(msg, err1, err2) + self.fail() + else: + self.set_stopped() +
    +
    [docs] def wait_local_port(self, endpoint): + """ Waits until the local_port file for the endpoint is generated, + and returns the port number + + """ + return self.wait_file(endpoint, "local_port") +
    +
    [docs] def wait_result(self, endpoint): + """ Waits until the return code file for the endpoint is generated + + """ + return self.wait_file(endpoint, "ret_file") +
    +
    [docs] def wait_file(self, endpoint, filename): + """ Waits until file on endpoint is generated """ + result = None + delay = 1.0 + + node = self.endpoint_node(endpoint) + run_home = self.run_home(endpoint) + + for i in xrange(20): + (out, err), proc = node.check_output(run_home, filename) + + if out: + result = out.strip() + break + else: + time.sleep(delay) + delay = delay * 1.5 + else: + msg = "Couldn't retrieve %s" % filename + self.error(msg, out, err) + raise RuntimeError, msg + + return result +
    +
    [docs] def initiate(self, endpoint, remote_endpoint, address, cipher, cipher_key, + bwlimit, txqueuelen): + + command = self._initiate_command(endpoint, remote_endpoint, + address, cipher, cipher_key, bwlimit, txqueuelen) + + node = self.endpoint_node(endpoint) + run_home = self.run_home(endpoint) + app_home = self.app_home(endpoint) + + # upload command to connect.sh script + shfile = os.path.join(app_home, "fd-udp-connect.sh") + node.upload_command(command, + shfile = shfile, + overwrite = False) + + # invoke connect script + cmd = "bash %s" % shfile + (out, err), proc = node.run(cmd, run_home) + + # check if execution errors occurred + msg = "Failed to connect endpoints " + + if proc.poll(): + self.error(msg, out, err) + raise RuntimeError, msg + + # Wait for pid file to be generated + pid, ppid = node.wait_pid(run_home) + + self._pids[endpoint] = (pid, ppid) + + # Check for error information on the remote machine + (out, err), proc = node.check_errors(run_home) + # Out is what was written in the stderr file + if err: + msg = " Failed to start command '%s' " % command + self.error(msg, out, err) + raise RuntimeError, msg + + port = self.wait_local_port(endpoint) + + return port +
    + def _initiate_command(self, endpoint, remote_endpoint, address, + cipher, cipher_key, bwlimit, txqueuelen): + local_node = self.endpoint_node(endpoint) + local_run_home = self.run_home(endpoint) + local_app_home = self.app_home(endpoint) + remote_node = self.endpoint_node(remote_endpoint) + + local_ip = local_node.get("ip") + remote_ip = remote_node.get("ip") + + local_port_file = os.path.join(local_run_home, "local_port") + remote_port_file = os.path.join(local_run_home, "remote_port") + ret_file = os.path.join(local_run_home, "ret_file") + + address = base64.b64encode(address) + + command = [""] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/fd-udp-connect.py") + command.append("-a %s" % address) + command.append("-p %s" % local_port_file) + command.append("-P %s" % remote_port_file) + command.append("-o %s" % local_ip) + command.append("-O %s" % remote_ip) + command.append("-R %s" % ret_file) + command.append("-t %s" % "IFF_TAP") + if self.pi: + command.append("-n") + if cipher: + command.append("-c %s" % cipher) + if cipher_key: + command.append("-k %s " % cipher_key) + if txqueuelen: + command.append("-q %s " % txqueuelen) + if bwlimit: + command.append("-b %s " % bwlimit) + + command = " ".join(command) + command = self.replace_paths(command, node=local_node, + app_home=local_app_home, run_home=local_run_home) + + return command + +
    [docs] def establish(self, endpoint, remote_endpoint, port): + node = self.endpoint_node(endpoint) + run_home = self.run_home(endpoint) + + # upload remote port number to file + remote_port = "%s\n" % port + node.upload(remote_port, + os.path.join(run_home, "remote_port"), + text = True, + overwrite = False) +
    +
    [docs] def verify(self, endpoint): + self.wait_result(endpoint) +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3client.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3client.html new file mode 100644 index 00000000..af81026d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3client.html @@ -0,0 +1,208 @@ + + + + + + + + nepi.resources.linux.ns3.ns3client — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.ns3client

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import base64
    +import cPickle
    +import errno
    +import os
    +import socket
    +import time
    +import weakref
    +import threading
    +
    +from optparse import OptionParser, SUPPRESS_HELP
    +
    +from nepi.resources.ns3.ns3client import NS3Client
    +from nepi.resources.ns3.ns3server import NS3WrapperMessage
    +
    +
    [docs]class LinuxNS3Client(NS3Client): + def __init__(self, simulation): + super(LinuxNS3Client, self).__init__() + self._simulation = weakref.ref(simulation) + self._socket_lock = threading.Lock() + + @property +
    [docs] def simulation(self): + return self._simulation() +
    +
    [docs] def send_msg(self, msg_type, *args, **kwargs): + msg = [msg_type, args, kwargs] + + def encode(item): + item = cPickle.dumps(item) + return base64.b64encode(item) + + encoded = "|".join(map(encode, msg)) + + with self._socket_lock: + if self.simulation.node.get("hostname") in ['localhost', '127.0.0.1']: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(self.simulation.remote_socket) + sock.send("%s\n" % encoded) + reply = sock.recv(1024) + sock.close() + else: + command = ( "python -c 'import socket;" + "sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM);" + "sock.connect(\"%(socket_addr)s\");" + "msg = \"%(encoded_message)s\\n\";" + "sock.send(msg);" + "reply = sock.recv(1024);" + "sock.close();" + "print reply'") % { + "encoded_message": encoded, + "socket_addr": self.simulation.remote_socket, + } + + (reply, err), proc = self.simulation.node.execute(command, + with_lock = True) + + if (err and proc.poll()) or reply.strip() == "": + msg = (" Couldn't connect to remote socket %s - REPLY: %s " + "- ERROR: %s ") % ( + self.simulation.remote_socket, reply, err) + self.simulation.error(msg, reply, err) + raise RuntimeError(msg) + + reply = cPickle.loads(base64.b64decode(reply)) + + return reply +
    +
    [docs] def create(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.CREATE, *args, **kwargs) +
    +
    [docs] def factory(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.FACTORY, *args, **kwargs) +
    +
    [docs] def invoke(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.INVOKE, *args, **kwargs) +
    +
    [docs] def set(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.SET, *args, **kwargs) +
    +
    [docs] def get(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.GET, *args, **kwargs) +
    +
    [docs] def flush(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.FLUSH, *args, **kwargs) +
    +
    [docs] def start(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.START, *args, **kwargs) +
    +
    [docs] def stop(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.STOP, *args, **kwargs) +
    +
    [docs] def shutdown(self, *args, **kwargs): + try: + return self.send_msg(NS3WrapperMessage.SHUTDOWN, *args, **kwargs) + except: + pass + + return None +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3dceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3dceapplication.html new file mode 100644 index 00000000..b5c8d333 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3dceapplication.html @@ -0,0 +1,170 @@ + + + + + + + + nepi.resources.linux.ns3.ns3dceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.ns3dceapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.ns3.ns3dceapplication import NS3BaseDceApplication
    +
    +@clsinit_copy
    +
    [docs]class LinuxNS3DceApplication(NS3BaseDceApplication): + _rtype = "linux::ns3::dce::Application" + + @classmethod + def _register_attributes(cls): + sources = Attribute("sources", + "Path to tar.gz file with sources for the application execute in DCE. " + "Sources will be uploaded to ${SRC} and it is the responsibility of " + "the build instructions (in the build attribute) to copy the compiled " + "binaries to the ${BIN_DCE} directory", + flags = Flags.Design) + + build = Attribute("build", + "Instructions to compile sources DCE-compatible way. " + "Note that sources will be uploaded to ${SRC} and the " + "build instructions are responsible for copying the " + "binaries to the ${BIN_DCE} directory. ", + flags = Flags.Design) + + depends = Attribute("depends", + "Space-separated list of packages required to run the application", + flags = Flags.Design) + + cls._register_attribute(sources) + cls._register_attribute(build) + cls._register_attribute(depends) + + def _instantiate_object(self): + command = [] + + # Install package dependencies required to run the binary + depends = self.get("depends") + if depends: + dcmd = self.simulation.install_dependencies(depends = depends) + if dcmd: + command.append(dcmd) + + # Upload sources to generate the binary + sources = self.get("sources") + if sources: + scmd = self.simulation.upload_extra_sources(sources = sources) + if scmd: + command.append(scmd) + + # Upload instructions to build the binary + build = self.get("build") + if build: + bcmd = self.simulation.build(build = build) + if bcmd: + command.append(bcmd) + + if command: + deploy_command = ";".join(command) + prefix = "%d_deploy" % self.guid + self.simulation.execute_deploy_command(deploy_command, prefix=prefix) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3pingdceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3pingdceapplication.html new file mode 100644 index 00000000..d4d6d766 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3pingdceapplication.html @@ -0,0 +1,345 @@ + + + + + + + + nepi.resources.linux.ns3.ns3pingdceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.ns3pingdceapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.ns3.ns3dceapplication import LinuxNS3DceApplication
    +
    +@clsinit_copy
    +
    [docs]class LinuxDcePing(LinuxNS3DceApplication): + _rtype = "linux::ns3::dce::Ping" + + @classmethod + def _register_attributes(cls): + count = Attribute("count", + "Sets ping -c option. Determines the number of ECHO_REQUEST " + "packates to send before stopping.", + type = Types.Integer, + flags = Flags.Design) + + mark = Attribute("mark", + "Sets ping -m option. Uses 'mark' to tag outgoing packets. ", + flags = Flags.Design) + + interval = Attribute("interval", + "Sets ping -i option. Leaves interval seconds between " + "successive ECHO_REUQEST packets. ", + flags = Flags.Design) + + address = Attribute("address", + "Sets ping -I option. Sets ECHO_REQUEST packets souce address " + "to the specified interface address ", + flags = Flags.Design) + + preload = Attribute("preload", + "Sets ping -l option. Sends preload amount of packets " + "without waiting for a reply ", + flags = Flags.Design) + + numeric = Attribute("numeric", + "Sets ping -n option. Disables resolution of host addresses into " + "symbolic names. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + pattern = Attribute("pattern", + "Sets ping -p option. Species a up to 16 ''pad'' bytes to fill " + "out sent packets. ", + flags = Flags.Design) + + printtmp = Attribute("printTimestamp", + "Sets ping -D option. Prints timestamp befor each line as: " + "unix time + microseconds as in gettimeofday ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + tos = Attribute("tos", + "Sets ping -Q option. Sets Quality of Service related bits in ICMP " + "datagrams. tos can be either a decimal or hexadecime number ", + flags = Flags.Design) + + quiet = Attribute("quiet", + "Sets ping -q option. Disables ping standard output ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + rec_route = Attribute("recordRoute", + "Sets ping -R option. Includes the RECORD_ROUTE option in the " + "ECHO REQUEST packet and displays route buffer on the Disables " + "ping standard output.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + route_bypass = Attribute("routeBypass", + "Sets ping -r option. Bypasses normal routing tables and sends " + "ECHO REQUEST packets directly yo a host on an attached interface. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + packetsize = Attribute("packetSize", + "Sets ping -s option. Specifies the number of data bytes to be " + "sent. Defaults to 56. ", + flags = Flags.Design) + + sendbuff = Attribute("sendBuff", + "Sets ping -S option. Specifies the number of packets to buffer. " + "Defaults to one. ", + flags = Flags.Design) + + ttl = Attribute("ttl", + "Sets ping -t option. Specifies the IP Time to Live for the " + "packets. ", + flags = Flags.Design) + + timestamp = Attribute("timestamp", + "Sets ping -T option. Sets special IP timestamp options. ", + flags = Flags.Design) + + hint = Attribute("hint", + "Sets ping -M option. Selects Path MTU Discovery strategy. ", + flags = Flags.Design) + + full_latency = Attribute("fullLatency", + "Sets ping -U option. Calculates round trip time taking into " + "account the full user-to-user latency instead of only the " + "network round trip time. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + verbose = Attribute("verbose", + "Sets ping -v option. Verbose output. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + flood = Attribute("flood", + "Sets ping -f option. Flood ping. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + deadline = Attribute("deadline", + "Sets ping -w option. Specify a timeout, in seconds, before ping " + "exits regardless of how many packets have been sent or received.", + flags = Flags.Design) + + timeout = Attribute("timeout", + "Sets ping -W option. Time to wait for a respone in seconds .", + flags = Flags.Design) + + target = Attribute("target", + "The host to ping .", + flags = Flags.Design) + + cls._register_attribute(count) + cls._register_attribute(mark) + cls._register_attribute(interval) + cls._register_attribute(address) + cls._register_attribute(preload) + cls._register_attribute(numeric) + cls._register_attribute(pattern) + cls._register_attribute(printtmp) + cls._register_attribute(tos) + cls._register_attribute(quiet) + cls._register_attribute(rec_route) + cls._register_attribute(route_bypass) + cls._register_attribute(packetsize) + cls._register_attribute(sendbuff) + cls._register_attribute(ttl) + cls._register_attribute(timestamp) + cls._register_attribute(hint) + cls._register_attribute(full_latency) + cls._register_attribute(verbose) + cls._register_attribute(flood) + cls._register_attribute(deadline) + cls._register_attribute(timeout) + cls._register_attribute(target) + + def _instantiate_object(self): + self.set("sources", self._sources) + self.set("build", self._build) + self.set("binary", "ping") + self.set("arguments", self._arguments) + + super(LinuxDcePing, self)._instantiate_object() + + @property + def _sources(self): + return "http://www.skbuff.net/iputils/iputils-s20101006.tar.bz2" + + @property + def _build(self): + return (" ( " + " test -f ${BIN_DCE}/ping && " + " echo 'binaries found, nothing to do' " + " ) || ( " + "tar xvjf ${SRC}/iputils-s20101006.tar.bz2 && " + "cd iputils-s20101006/ && " + "sed -i 's/CFLAGS=/CFLAGS+=/g' Makefile && " + "make CFLAGS=-fPIC LDFLAGS='-pie -rdynamic' ping && " + "cp ping ${BIN_DCE} && cd - " + " )" + ) + + @property + def _arguments(self): + args = [] + + if self.get("count"): + args.append("-c %s" % self.get("count")) + if self.get("mark"): + args.append("-m %s" % self.get("mark")) + if self.get("interval"): + args.append("-i %s" % self.get("interval")) + if self.get("address"): + args.append("-I %s" % self.get("address")) + if self.get("preload"): + args.append("-l %s" % self.get("preload")) + if self.get("numeric") == True: + args.append("-n") + if self.get("pattern"): + args.append("-p %s" % self.get("pattern")) + if self.get("tos"): + args.append("-Q %s" % self.get("tos")) + if self.get("quiet"): + args.append("-q %s" % self.get("quiet")) + if self.get("recordRoute") == True: + args.append("-R") + if self.get("routeBypass") == True: + args.append("-r") + if self.get("packetSize"): + args.append("-s %s" % self.get("packetSize")) + if self.get("sendBuff"): + args.append("-S %s" % self.get("sendBuff")) + if self.get("ttl"): + args.append("-t %s" % self.get("ttl")) + if self.get("timestamp"): + args.append("-T %s" % self.get("timestamp")) + if self.get("hint"): + args.append("-M %s" % self.get("hint")) + if self.get("fullLatency") == True: + args.append("-U") + if self.get("verbose") == True: + args.append("-v") + if self.get("flood") == True: + args.append("-f") + if self.get("deadline"): + args.append("-w %s" % self.get("deadline")) + if self.get("timeout"): + args.append("-W %s" % self.get("timeout")) + args.append(self.get("target")) + + return ";".join(args) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3simulation.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3simulation.html new file mode 100644 index 00000000..a7ecfa5c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3simulation.html @@ -0,0 +1,827 @@ + + + + + + + + nepi.resources.linux.ns3.ns3simulation — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.ns3simulation

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState, ResourceFactory
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.util.timefuncs import tnow, tdiffsec
    +from nepi.resources.ns3.ns3simulation import NS3Simulation
    +from nepi.resources.ns3.ns3wrapper import SIMULATOR_UUID, GLOBAL_VALUE_UUID, \
    +        IPV4_GLOBAL_ROUTING_HELPER_UUID
    +from nepi.resources.linux.ns3.ns3client import LinuxNS3Client
    +
    +import os
    +import time
    +import threading
    +
    +@clsinit_copy
    +
    [docs]class LinuxNS3Simulation(LinuxApplication, NS3Simulation): + _rtype = "linux::ns3::Simulation" + + @classmethod + def _register_attributes(cls): + impl_type = Attribute("simulatorImplementationType", + "The object class to use as the simulator implementation", + allowed = ["ns3::DefaultSimulatorImpl", "ns3::RealtimeSimulatorImpl"], + default = "ns3::DefaultSimulatorImpl", + type = Types.Enumerate, + flags = Flags.Design) + + sched_type = Attribute("schedulerType", + "The object class to use as the scheduler implementation", + allowed = ["ns3::MapScheduler", + "ns3::ListScheduler", + "ns3::HeapScheduler", + "ns3::MapScheduler", + "ns3::CalendarScheduler" + ], + default = "ns3::MapScheduler", + type = Types.Enumerate, + flags = Flags.Design) + + check_sum = Attribute("checksumEnabled", + "A global switch to enable all checksums for all protocols", + default = False, + type = Types.Bool, + flags = Flags.Design) + + ns_log = Attribute("nsLog", + "NS_LOG environment variable. " \ + " Will only generate output if ns-3 is compiled in DEBUG mode. ", + flags = Flags.Design) + + verbose = Attribute("verbose", + "True to output debugging info from the ns3 client-server communication", + type = Types.Bool, + flags = Flags.Design) + + enable_dump = Attribute("enableDump", + "Enable dumping the remote executed ns-3 commands to a script " + "in order to later reproduce and debug the experiment", + type = Types.Bool, + default = False, + flags = Flags.Design) + + build_mode = Attribute("buildMode", + "Mode used to build ns-3 with waf. One if: debug, release, oprimized ", + default = "optimized", + allowed = ["debug", "release", "optimized"], + type = Types.Enumerate, + flags = Flags.Design) + + ns3_version = Attribute("ns3Version", + "Version of ns-3 to install from nsam repo", + default = "ns-3.20", + #default = "ns-3-dev", + flags = Flags.Design) + + pybindgen_version = Attribute("pybindgenVersion", + "Version of pybindgen to install from bazar repo", + default = "868", + #default = "876", + flags = Flags.Design) + + dce_version = Attribute("dceVersion", + "Version of dce to install from nsam repo (tag branch for repo)", + #default = "dce-1.3", + default = "dce-dev", + flags = Flags.Design) + + populate_routing_tables = Attribute("populateRoutingTables", + "Invokes Ipv4GlobalRoutingHelper.PopulateRoutingTables() ", + default = False, + type = Types.Bool, + flags = Flags.Design) + + stoptime = Attribute("StopTime", + "Time at which the simulation will stop", + flags = Flags.Design) + + cls._register_attribute(impl_type) + cls._register_attribute(sched_type) + cls._register_attribute(check_sum) + cls._register_attribute(ns_log) + cls._register_attribute(enable_dump) + cls._register_attribute(verbose) + cls._register_attribute(build_mode) + cls._register_attribute(ns3_version) + cls._register_attribute(pybindgen_version) + cls._register_attribute(dce_version) + cls._register_attribute(populate_routing_tables) + cls._register_attribute(stoptime) + + def __init__(self, ec, guid): + LinuxApplication.__init__(self, ec, guid) + NS3Simulation.__init__(self) + + self._client = None + self._home = "ns3-simu-%s" % self.guid + self._socket_name = "ns3-%s.sock" % os.urandom(4).encode('hex') + self._enable_dce = None + self._dce_helper = None + + @property +
    [docs] def socket_name(self): + return self._socket_name +
    + @property +
    [docs] def remote_socket(self): + return os.path.join(self.run_home, self.socket_name) +
    +
    [docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + # stout needs to get flushed on the ns-3 server side, else we will + # get an empty stream. We try twice to retrieve the stream + # if we get empty stdout since the stream might not be + # flushed immediately. + if name.endswith("stdout"): + self._client.flush() + result = LinuxApplication.trace(self, name, attr, block, offset) + if result: + return result + # Let the stream be flushed + time.sleep(1) + + return LinuxApplication.trace(self, name, attr, block, offset) +
    +
    [docs] def upload_sources(self): + self.node.mkdir(os.path.join(self.node.src_dir, "ns3wrapper")) + + # upload ns3 wrapper python script + ns3_wrapper = os.path.join(os.path.dirname(__file__), "..", "..", "ns3", + "ns3wrapper.py") + + self.node.upload(ns3_wrapper, + os.path.join(self.node.src_dir, "ns3wrapper", "ns3wrapper.py"), + overwrite = False) + + # upload ns3 wrapper debug python script + ns3_wrapper_debug = os.path.join(os.path.dirname(__file__), "..", "..", "ns3", + "ns3wrapper_debug.py") + + self.node.upload(ns3_wrapper_debug, + os.path.join(self.node.src_dir, "ns3wrapper", "ns3wrapper_debug.py"), + overwrite = False) + + # upload ns3_server python script + ns3_server = os.path.join(os.path.dirname(__file__), "..", "..", "ns3", + "ns3server.py") + + self.node.upload(ns3_server, + os.path.join(self.node.src_dir, "ns3wrapper", "ns3server.py"), + overwrite = False) + + if self.node.use_rpm: + # upload pygccxml sources + pygccxml_tar = os.path.join(os.path.dirname(__file__), "dependencies", + "%s.tar.gz" % self.pygccxml_version) + + self.node.upload(pygccxml_tar, + os.path.join(self.node.src_dir, "%s.tar.gz" % self.pygccxml_version), + overwrite = False) + + # Upload user defined ns-3 sources + self.node.mkdir(os.path.join(self.node.src_dir, "ns-3")) + src_dir = os.path.join(self.node.src_dir, "ns-3") + + super(LinuxNS3Simulation, self).upload_sources(src_dir = src_dir) +
    +
    [docs] def upload_extra_sources(self, sources = None, src_dir = None): + return super(LinuxNS3Simulation, self).upload_sources( + sources = sources, + src_dir = src_dir) +
    +
    [docs] def upload_start_command(self): + command = self.get("command") + env = self.get("env") + + # We want to make sure the ccnd is running + # before the experiment starts. + # Run the command as a bash script in background, + # in the host ( but wait until the command has + # finished to continue ) + env = self.replace_paths(env) + command = self.replace_paths(command) + + shfile = os.path.join(self.app_home, "start.sh") + self.node.upload_command(command, + shfile = shfile, + env = env, + overwrite = True) + + # Run the ns3wrapper + self._run_in_background() + + # Wait until the remote socket is created + self.wait_remote_socket() +
    +
    [docs] def configure(self): + if self.has_changed("simulatorImplementationType"): + simu_type = self.get("simulatorImplementationType") + stype = self.create("StringValue", simu_type) + self.invoke(GLOBAL_VALUE_UUID, "Bind", "SimulatorImplementationType", stype) + + if self.has_changed("checksumEnabled"): + check_sum = self.get("checksumEnabled") + btrue = self.create("BooleanValue", check_sum) + self.invoke(GLOBAL_VALUE_UUID, "Bind", "ChecksumEnabled", btrue) + + if self.has_changed("schedulerType"): + sched_type = self.get("schedulerType") + stype = self.create("StringValue", sched_type) + self.invoke(GLOBAL_VALUE_UUID, "Bind", "SchedulerType", btrue) +
    +
    [docs] def do_deploy(self): + if not self.node or self.node.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + + # ccnd needs to wait until node is deployed and running + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("depends"): + self.set("depends", self._dependencies) + + if self.get("sources"): + sources = self.get("sources") + source = sources.split(" ")[0] + basename = os.path.basename(source) + version = ( basename.strip().replace(".tar.gz", "") + .replace(".tar","") + .replace(".gz","") + .replace(".zip","") ) + + self.set("ns3Version", version) + self.set("sources", source) + + if not self.get("build"): + self.set("build", self._build) + + if not self.get("install"): + self.set("install", self._install) + + if not self.get("env"): + self.set("env", self._environment) + + self.do_discover() + self.do_provision() + + # Create client + self._client = LinuxNS3Client(self) + + self.configure() + + self.set_ready() +
    +
    [docs] def do_start(self): + """ Starts simulation execution + + """ + self.info("Starting") + + if self.state == ResourceState.READY: + if self.get("populateRoutingTables") == True: + self.invoke(IPV4_GLOBAL_ROUTING_HELPER_UUID, "PopulateRoutingTables") + + time = self.get("StopTime") + if time: + self._client.stop(time=time) + + self._client.start() + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def do_stop(self): + """ Stops simulation execution + + """ + if self.state == ResourceState.STARTED: + if not self.get("StopTime"): + self._client.stop() + self.set_stopped() +
    +
    [docs] def do_release(self): + self.info("Releasing resource") + + tear_down = self.get("tearDown") + if tear_down: + self.node.execute(tear_down) + + self.do_stop() + self._client.shutdown() + LinuxApplication.do_stop(self) + + super(LinuxApplication, self).do_release() +
    + @property +
    [docs] def state(self): + super(LinuxApplication, self).state + + if self._state == ResourceState.STARTED: + try: + is_finished = self.invoke(SIMULATOR_UUID, "isFinished") + + if is_finished: + self.set_stopped() + except: + msg = "Simulator failed. Can not retrieve state" + out = "" + + import traceback + err = traceback.format_exc() + self.error(msg, out, err) + self.do_fail() + + return self._state +
    + @property +
    [docs] def enable_dce(self): + if self._enable_dce is None: + from nepi.resources.ns3.ns3dceapplication import NS3BaseDceApplication + rclass = ResourceFactory.get_resource_type( + NS3BaseDceApplication.get_rtype()) + + self._enable_dce = False + for guid in self.ec.resources: + rm = self.ec.get_resource(guid) + if isinstance(rm, rclass): + self._enable_dce = True + + from nepi.resources.ns3.ns3dcehelper import NS3DceHelper + self._dce_helper = NS3DceHelper(self) + break + + return self._enable_dce +
    + @property +
    [docs] def dce_helper(self): + return self._dce_helper +
    + @property + def _start_command(self): + command = [] + + command.append("PYTHONPATH=$PYTHONPATH:${SRC}/ns3wrapper/") + + command.append("python ${SRC}/ns3wrapper/ns3server.py -S %s" % \ + os.path.basename(self.remote_socket) ) + + ns_log = self.get("nsLog") + if ns_log: + command.append("-L '%s'" % ns_log) + + if self.get("enableDump"): + command.append("-D") + + if self.get("verbose"): + command.append("-v") + + command = " ".join(command) + return command + + @property + def _dependencies(self): + if self.node.use_rpm: + return ( " gcc gcc-c++ python python-devel mercurial bzr tcpdump socat gccxml unzip") + elif self.node.use_deb: + return ( " gcc g++ python python-dev mercurial bzr tcpdump socat gccxml python-pygccxml unzip") + return "" + + @property +
    [docs] def ns3_repo(self): + return "http://code.nsnam.org" +
    + @property +
    [docs] def pygccxml_version(self): + return "pygccxml-1.0.0" +
    + @property +
    [docs] def dce_repo(self): + return "http://code.nsnam.org/ns-3-dce" + #eturn "http://code.nsnam.org/epmancini/ns-3-dce" +
    + @property +
    [docs] def dce_version(self): + dce_version = self.get("dceVersion") + return dce_version or "dce-dev" +
    + @property +
    [docs] def ns3_build_location(self): + location = "${BIN}/ns-3/%(ns3_version)s%(dce_version)s/%(build_mode)s/build" \ + % { + "ns3_version": self.get("ns3Version"), + "dce_version": "-%s" % self.get("dceVersion") \ + if self.enable_dce else "", + "build_mode": self.get("buildMode"), + } + + return location + +
    + @property +
    [docs] def ns3_src_location(self): + location = "${SRC}/ns-3/%(ns3_version)s" \ + % { + "ns3_version": self.get("ns3Version"), + } + + return location +
    + @property +
    [docs] def dce_src_location(self): + location = "${SRC}/ns-3-dce/%(dce_version)s" \ + % { + "dce_version": self.get("dceVersion"), + } + + return location +
    + @property + def _clone_ns3_command(self): + source = self.get("sources") + + if not source: + clone_ns3_cmd = "hg clone %(ns3_repo)s/%(ns3_version)s %(ns3_src)s" \ + % { + "ns3_version": self.get("ns3Version"), + "ns3_repo": self.ns3_repo, + "ns3_src": self.ns3_src_location, + } + else: + if source.find(".tar.gz") > -1: + clone_ns3_cmd = ( + "tar xzf ${SRC}/ns-3/%(basename)s " + " --strip-components=1 -C %(ns3_src)s" + ) % { + "basename": os.path.basename(source), + "ns3_src": self.ns3_src_location, + } + elif source.find(".tar") > -1: + clone_ns3_cmd = ( + "tar xf ${SRC}/ns-3/%(basename)s " + " --strip-components=1 -C %(ns3_src)s" + ) % { + "basename": os.path.basename(source), + "ns3_src": self.ns3_src_location, + } + elif source.find(".zip") > -1: + basename = os.path.basename(source) + bare_basename = basename.replace(".zip", "") + + clone_ns3_cmd = ( + "unzip ${SRC}/ns-3/%(basename)s && " + "mv ${SRC}/ns-3/%(bare_basename)s %(ns3_src)s" + ) % { + "bare_basename": basename_name, + "basename": basename, + "ns3_src": self.ns3_src_location, + } + + return clone_ns3_cmd + + @property + def _clone_dce_command(self): + clone_dce_cmd = " echo 'DCE will not be built' " + + if self.enable_dce: + dce_version = self.dce_version + dce_tag = "" + if dce_version != "dce-dev": + dce_tag = "-r %s" % dce_version + + clone_dce_cmd = ( + # DCE installation + # Test if dce is alredy cloned + " ( " + " ( " + " ( test -d %(dce_src)s ) " + " && echo 'dce binaries found, nothing to do'" + " ) " + " ) " + " || " + # Get dce source code + " ( " + " mkdir -p %(dce_src)s && " + " hg clone %(dce_repo)s %(dce_tag)s %(dce_src)s" + " ) " + ) % { + "dce_repo": self.dce_repo, + "dce_tag": dce_tag, + "dce_src": self.dce_src_location, + } + + return clone_dce_cmd + + @property + def _build(self): + # If the user defined local sources for ns-3, we uncompress the sources + # on the remote sources directory. Else we clone ns-3 from the official repo. + clone_ns3_cmd = self._clone_ns3_command + clone_dce_cmd = self._clone_dce_command + + ns3_build_cmd = ( + # NS3 installation + "( " + " ( " + # Test if ns-3 is alredy cloned + " ((( test -d %(ns3_src)s ) || " + " ( test -d ${NS3BINDINGS:='None'} && test -d ${NS3LIBRARIES:='None'})) " + " && echo 'ns-3 binaries found, nothing to do' )" + " ) " + " || " + # If not, install ns-3 and its dependencies + " ( " + # Install pygccxml + " ( " + " ( " + " python -c 'import pygccxml' && " + " echo 'pygccxml not found' " + " ) " + " || " + " ( " + " tar xf ${SRC}/%(pygccxml_version)s.tar.gz -C ${SRC} && " + " cd ${SRC}/%(pygccxml_version)s && " + " python setup.py build && " + " sudo -S python setup.py install " + " ) " + " ) " + # Install pybindgen + " && " + " ( " + " ( " + " test -d ${SRC}/pybindgen/%(pybindgen_version)s && " + " echo 'binaries found, nothing to do' " + " ) " + " || " + # If not, clone and build + " ( cd ${SRC} && " + " mkdir -p ${SRC}/pybindgen && " + " bzr checkout lp:pybindgen -r %(pybindgen_version)s ${SRC}/pybindgen/%(pybindgen_version)s && " + " cd ${SRC}/pybindgen/%(pybindgen_version)s && " + " ./waf configure && " + " ./waf " + " ) " + " ) " + " && " + # Get ns-3 source code + " ( " + " mkdir -p %(ns3_src)s && " + " %(clone_ns3_cmd)s " + " ) " + " ) " + ") " + " && " + "( " + " %(clone_dce_cmd)s " + ") " + ) % { + "ns3_src": self.ns3_src_location, + "pybindgen_version": self.get("pybindgenVersion"), + "pygccxml_version": self.pygccxml_version, + "clone_ns3_cmd": clone_ns3_cmd, + "clone_dce_cmd": clone_dce_cmd, + } + + return ns3_build_cmd + + @property + def _install_dce_command(self): + install_dce_cmd = " echo 'DCE will not be installed'" + + if self.enable_dce: + install_dce_cmd = ( + " ( " + " ((test -d %(ns3_build)s/bin_dce ) && " + " echo 'dce binaries found, nothing to do' )" + " ) " + " ||" + " ( " + # If not, copy build to dce + " cd %(dce_src)s && " + " rm -rf %(dce_src)s/build && " + " ./waf configure %(enable_opt)s --with-pybindgen=${SRC}/pybindgen/%(pybindgen_version)s " + " --prefix=%(ns3_build)s --with-ns3=%(ns3_build)s && " + " ./waf build && " + " ./waf install && " + " [ ! -e %(ns3_build)s/lib/python/site-packages/ns/dce.so ] && " + " mv %(ns3_build)s/lib*/python*/site-packages/ns/dce.so %(ns3_build)s/lib/python/site-packages/ns/ " + " )" + ) % { + "pybindgen_version": self.get("pybindgenVersion"), + "enable_opt": "--enable-opt" if self.get("buildMode") == "optimized" else "", + "ns3_build": self.ns3_build_location, + "dce_src": self.dce_src_location, + } + + return install_dce_cmd + + @property + def _install(self): + install_dce_cmd = self._install_dce_command + + install_ns3_cmd = ( + # Test if ns-3 is alredy installed + "(" + " ( " + " ( ( (test -d %(ns3_build)s/lib ) || " + " (test -d ${NS3BINDINGS:='None'} && test -d ${NS3LIBRARIES:='None'}) ) && " + " echo 'binaries found, nothing to do' )" + " ) " + " ||" + " ( " + # If not, copy ns-3 build to bin + " mkdir -p %(ns3_build)s && " + " cd %(ns3_src)s && " + " rm -rf %(ns3_src)s/build && " + " ./waf configure -d %(build_mode)s --with-pybindgen=${SRC}/pybindgen/%(pybindgen_version)s " + " --prefix=%(ns3_build)s && " + " ./waf build && " + " ./waf install && " + " mv %(ns3_build)s/lib*/python* %(ns3_build)s/lib/python " + " )" + ") " + " && " + "( " + " %(install_dce_cmd)s " + ") " + ) % { + "pybindgen_version": self.get("pybindgenVersion"), + "build_mode": self.get("buildMode"), + "install_dce_cmd": install_dce_cmd, + "ns3_build": self.ns3_build_location, + "ns3_src": self.ns3_src_location, + } + + return install_ns3_cmd + + @property + def _environment(self): + env = [] + env.append("PYTHONPATH=$PYTHONPATH:${NS3BINDINGS:=%(ns3_build)s/lib/python/site-packages}" % { + "ns3_build": self.ns3_build_location + }) + # If NS3LIBRARIES is defined and not empty, assign its value, + # if not assign ns3_build_home/lib/ to NS3LIBRARIES and LD_LIBARY_PATH + env.append("LD_LIBRARY_PATH=${NS3LIBRARIES:=%(ns3_build)s/lib}" % { + "ns3_build": self.ns3_build_location + }) + env.append("DCE_PATH=$NS3LIBRARIES/../bin_dce") + env.append("DCE_ROOT=$NS3LIBRARIES/..") + + return " ".join(env) + +
    [docs] def replace_paths(self, command): + """ + Replace all special path tags with shell-escaped actual paths. + """ + return ( command + .replace("${USR}", self.node.usr_dir) + .replace("${LIB}", self.node.lib_dir) + .replace("${BIN}", self.node.bin_dir) + .replace("${SRC}", self.node.src_dir) + .replace("${SHARE}", self.node.share_dir) + .replace("${EXP}", self.node.exp_dir) + .replace("${EXP_HOME}", self.node.exp_home) + .replace("${APP_HOME}", self.app_home) + .replace("${RUN_HOME}", self.run_home) + .replace("${NODE_HOME}", self.node.node_home) + .replace("${HOME}", self.node.home_dir) + # If NS3LIBRARIES is defined and not empty, use that value, + # if not use ns3_build_home/lib/ + .replace("${BIN_DCE}", "${NS3LIBRARIES-%s/lib}/../bin_dce" % \ + self.ns3_build_location) + ) +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    +
    [docs] def wait_remote_socket(self): + """ Waits until the remote socket is created + """ + command = " [ -e %s ] && echo 'DONE' " % self.remote_socket + + for i in xrange(200): + (out, err), proc = self.node.execute(command, retry = 1, + with_lock = True) + + if out.find("DONE") > -1: + break + else: + raise RuntimeError("Remote socket not found at %s" % \ + self.remote_socket) + +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/tuntapfdlink.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/tuntapfdlink.html new file mode 100644 index 00000000..7ca4fe91 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/tuntapfdlink.html @@ -0,0 +1,251 @@ + + + + + + + + nepi.resources.linux.ns3.tuntapfdlink — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ns3.tuntapfdlink

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +from nepi.execution.resource import ResourceState, clsinit_copy
    +from nepi.resources.linux.application import LinuxApplication
    +
    +import base64
    +import fcntl
    +import os
    +import socket
    +import struct
    +
    +@clsinit_copy
    +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ping.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ping.html new file mode 100644 index 00000000..e019c1eb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ping.html @@ -0,0 +1,372 @@ + + + + + + + + nepi.resources.linux.ping — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.ping

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState 
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.util.timefuncs import tnow
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxPing(LinuxApplication): + _rtype = "linux::Ping" + + @classmethod + def _register_attributes(cls): + count = Attribute("count", + "Sets ping -c option. Determines the number of ECHO_REQUEST " + "packates to send before stopping.", + type = Types.Integer, + flags = Flags.Design) + + mark = Attribute("mark", + "Sets ping -m option. Uses 'mark' to tag outgoing packets. ", + flags = Flags.Design) + + interval = Attribute("interval", + "Sets ping -i option. Leaves interval seconds between " + "successive ECHO_REUQEST packets. ", + flags = Flags.Design) + + address = Attribute("address", + "Sets ping -I option. Sets ECHO_REQUEST packets souce address " + "to the specified interface address ", + flags = Flags.Design) + + preload = Attribute("preload", + "Sets ping -l option. Sends preload amount of packets " + "without waiting for a reply ", + flags = Flags.Design) + + numeric = Attribute("numeric", + "Sets ping -n option. Disables resolution of host addresses into " + "symbolic names. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + pattern = Attribute("pattern", + "Sets ping -p option. Species a up to 16 ''pad'' bytes to fill " + "out sent packets. ", + flags = Flags.Design) + + printtmp = Attribute("printTimestamp", + "Sets ping -D option. Prints timestamp befor each line as: " + "unix time + microseconds as in gettimeofday ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + tos = Attribute("tos", + "Sets ping -Q option. Sets Quality of Service related bits in ICMP " + "datagrams. tos can be either a decimal or hexadecime number ", + flags = Flags.Design) + + quiet = Attribute("quiet", + "Sets ping -q option. Disables ping standard output ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + rec_route = Attribute("recordRoute", + "Sets ping -R option. Includes the RECORD_ROUTE option in the " + "ECHO REQUEST packet and displays route buffer on the Disables " + "ping standard output.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + route_bypass = Attribute("routeBypass", + "Sets ping -r option. Bypasses normal routing tables and sends " + "ECHO REQUEST packets directly yo a host on an attached interface. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + packetsize = Attribute("packetSize", + "Sets ping -s option. Specifies the number of data bytes to be " + "sent. Defaults to 56. ", + flags = Flags.Design) + + sendbuff = Attribute("sendBuff", + "Sets ping -S option. Specifies the number of packets to buffer. " + "Defaults to one. ", + flags = Flags.Design) + + ttl = Attribute("ttl", + "Sets ping -t option. Specifies the IP Time to Live for the " + "packets. ", + flags = Flags.Design) + + timestamp = Attribute("timestamp", + "Sets ping -T option. Sets special IP timestamp options. ", + flags = Flags.Design) + + hint = Attribute("hint", + "Sets ping -M option. Selects Path MTU Discovery strategy. ", + flags = Flags.Design) + + full_latency = Attribute("fullLatency", + "Sets ping -U option. Calculates round trip time taking into " + "account the full user-to-user latency instead of only the " + "network round trip time. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + verbose = Attribute("verbose", + "Sets ping -v option. Verbose output. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + flood = Attribute("flood", + "Sets ping -f option. Flood ping. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + deadline = Attribute("deadline", + "Sets ping -w option. Specify a timeout, in seconds, before ping " + "exits regardless of how many packets have been sent or received.", + flags = Flags.Design) + + timeout = Attribute("timeout", + "Sets ping -W option. Time to wait for a respone in seconds .", + flags = Flags.Design) + + target = Attribute("target", + "The host to ping .", + flags = Flags.Design) + + early_start = Attribute("earlyStart", + "Start ping as early as deployment. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + cls._register_attribute(count) + cls._register_attribute(mark) + cls._register_attribute(interval) + cls._register_attribute(address) + cls._register_attribute(preload) + cls._register_attribute(numeric) + cls._register_attribute(pattern) + cls._register_attribute(printtmp) + cls._register_attribute(tos) + cls._register_attribute(quiet) + cls._register_attribute(rec_route) + cls._register_attribute(route_bypass) + cls._register_attribute(packetsize) + cls._register_attribute(sendbuff) + cls._register_attribute(ttl) + cls._register_attribute(timestamp) + cls._register_attribute(hint) + cls._register_attribute(full_latency) + cls._register_attribute(verbose) + cls._register_attribute(flood) + cls._register_attribute(deadline) + cls._register_attribute(timeout) + cls._register_attribute(target) + cls._register_attribute(early_start) + + def __init__(self, ec, guid): + super(LinuxPing, self).__init__(ec, guid) + self._home = "ping-%s" % self.guid + +
    [docs] def upload_start_command(self): + super(LinuxPing, self).upload_start_command() + + if self.get("earlyStart") == True: + self._run_in_background() +
    +
    [docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + super(LinuxPing, self).do_deploy() +
    +
    [docs] def do_start(self): + if self.get("earlyStart") == True: + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg + else: + super(LinuxPing, self).do_start() +
    + @property + def _start_command(self): + args = [] + + args.append("echo 'Starting PING to %s' ;" % self.get("target")) + + if self.get("printTimestamp") == True: + args.append("""echo "`date +'%Y%m%d%H%M%S'`";""") + + args.append("ping ") + + if self.get("count"): + args.append("-c %s" % self.get("count")) + if self.get("mark"): + args.append("-m %s" % self.get("mark")) + if self.get("interval"): + args.append("-i %s" % self.get("interval")) + if self.get("address"): + args.append("-I %s" % self.get("address")) + if self.get("preload"): + args.append("-l %s" % self.get("preload")) + if self.get("numeric") == True: + args.append("-n") + if self.get("pattern"): + args.append("-p %s" % self.get("pattern")) + if self.get("tos"): + args.append("-Q %s" % self.get("tos")) + if self.get("quiet"): + args.append("-q %s" % self.get("quiet")) + if self.get("recordRoute") == True: + args.append("-R") + if self.get("routeBypass") == True: + args.append("-r") + if self.get("packetSize"): + args.append("-s %s" % self.get("packetSize")) + if self.get("sendBuff"): + args.append("-S %s" % self.get("sendBuff")) + if self.get("ttl"): + args.append("-t %s" % self.get("ttl")) + if self.get("timestamp"): + args.append("-T %s" % self.get("timestamp")) + if self.get("hint"): + args.append("-M %s" % self.get("hint")) + if self.get("fullLatency") == True: + args.append("-U") + if self.get("verbose") == True: + args.append("-v") + if self.get("flood") == True: + args.append("-f") + if self.get("deadline"): + args.append("-w %s" % self.get("deadline")) + if self.get("timeout"): + args.append("-W %s" % self.get("timeout")) + args.append(self.get("target")) + + command = " ".join(args) + + return command + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/route.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/route.html new file mode 100644 index 00000000..a55f75f9 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/route.html @@ -0,0 +1,251 @@ + + + + + + + + nepi.resources.linux.route — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.route

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.application import LinuxApplication
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxRoute(LinuxApplication): + _rtype = "linux::Route" + _help = "Adds a route to the host using iptools " + + @classmethod + def _register_attributes(cls): + network = Attribute("network", "Network address", flags=Flags.Design) + prefix = Attribute("prefix", "IP prefix length", flags=Flags.Design) + nexthop = Attribute("nexthop", "Nexthop IP", flags=Flags.Design) + + cls._register_attribute(network) + cls._register_attribute(prefix) + cls._register_attribute(nexthop) + + def __init__(self, ec, guid): + super(LinuxRoute, self).__init__(ec, guid) + self._home = "route-%s" % self.guid + self._device = None + + @property +
    [docs] def device(self): + if not self._device: + from nepi.resources.linux.tap import LinuxTap + from nepi.resources.linux.tun import LinuxTun + from nepi.resources.linux.interface import LinuxInterface + tap = self.get_connected(LinuxTap.get_rtype()) + tun = self.get_connected(LinuxTun.get_rtype()) + interface = self.get_connected(LinuxInterface.get_rtype()) + if tap: self._device = tap[0] + elif tun: self._device = tun[0] + elif interface: self._device = interface[0] + else: + raise RuntimeError, "linux::Routes must be connected to a "\ + "linux::TAP, linux::TUN, or linux::Interface" + return self._device +
    + @property +
    [docs] def node(self): + return self.device.node +
    +
    [docs] def upload_start_command(self): + # We want to make sure the route is configured + # before the deploy is over, so we execute the + # start script now and wait until it finishes. + command = self.get("command") + command = self.replace_paths(command) + + shfile = os.path.join(self.app_home, "start.sh") + self.node.run_and_wait(command, self.run_home, + shfile = shfile, + overwrite = True) +
    +
    [docs] def upload_sources(self): + # upload stop.sh script + stop_command = self.replace_paths(self._stop_command) + + self.node.upload(stop_command, + os.path.join(self.app_home, "stop.sh"), + text = True, + # Overwrite file every time. + # The stop.sh has the path to the socket, which should change + # on every experiment run. + overwrite = True) +
    +
    [docs] def do_deploy(self): + if not self.device or self.device.state < ResourceState.PROVISIONED: + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("command"): + self.set("command", self._start_command) + + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def do_stop(self): + command = self.get('command') or '' + + if self.state == ResourceState.STARTED: + self.info("Stopping command '%s'" % command) + + command = "bash %s" % os.path.join(self.app_home, "stop.sh") + (out, err), proc = self.execute_command(command, + blocking = True) + + if err: + msg = " Failed to stop command '%s' " % command + self.error(msg, out, err) + + self.set_stopped() +
    + @property + def _start_command(self): + network = self.get("network") + prefix = self.get("prefix") + nexthop = self.get("nexthop") + devicename = self.device.get("deviceName") + + command = [] + command.append("sudo -S ip route add %s/%s %s dev %s" % ( + self.get("network"), + self.get("prefix"), + "default" if not nexthop else "via %s" % nexthop, + devicename)) + + return " ".join(command) + + @property + def _stop_command(self): + network = self.get("network") + prefix = self.get("prefix") + nexthop = self.get("nexthop") + devicename = self.device.get("deviceName") + + command = [] + command.append("sudo -S ip route del %s/%s %s dev %s" % ( + self.get("network"), + self.get("prefix"), + "default" if not nexthop else "via %s" % nexthop, + devicename)) + + return " ".join(command) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/rpmfuncs.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/rpmfuncs.html new file mode 100644 index 00000000..4503d568 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/rpmfuncs.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.linux.rpmfuncs — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.rpmfuncs

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +RPM_FUSION_URL = 'http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-stable.noarch.rpm'
    +RPM_FUSION_URL_F12 = 'http://download1.rpmfusion.org/free/fedora/releases/12/Everything/x86_64/os/rpmfusion-free-release-12-1.noarch.rpm'
    +RPM_FUSION_URL_F14 = 'http://download1.rpmfusion.org/free/fedora/releases/14/Everything/x86_64/os/rpmfusion-free-release-14-0.4.noarch.rpm'
    +
    +
    +# TODO: Investigate using http://nixos.org/nix/
    +
    +
    [docs]def install_packages_command(os, packages): + if not isinstance(packages, list): + packages = [packages] + + cmd = install_rpmfusion_command(os) + if cmd: cmd += " ; " + cmd += " && ".join(map(lambda p: + " { rpm -q %(package)s || sudo -S yum -y install --nogpgcheck %(package)s ; } " % { + 'package': p}, packages)) + + #cmd = { rpm -q rpmfusion-free-release || sudo -s rpm -i ... ; } && { rpm -q vim || sudo yum -y install vim ; } && .. + return cmd +
    +
    [docs]def remove_packages_command(os, packages): + if not isinstance(packages, list): + packages = [packages] + + cmd = " && ".join(map(lambda p: + " { rpm -q %(package)s && sudo -S yum -y remove %(package)s ; } " % { + 'package': p}, packages)) + + #cmd = { rpm -q vim && sudo yum -y remove vim ; } && .. + return cmd +
    +
    [docs]def install_rpmfusion_command(os): + from nepi.resources.linux.node import OSType + + cmd = " { rpm -q rpmfusion-free-release || sudo -S rpm -i %(package)s ; } " + + if (os & OSType.FEDORA_8): + # RpmFusion for Fedora 8 is unmaintained + cmd = "" + elif (os & OSType.FEDORA_12): + # For f12 + cmd = cmd % {'package': RPM_FUSION_URL_F12} + elif (os & OSType.FEDORA_14): + # For f14 + cmd = cmd % {'package': RPM_FUSION_URL_F14} + else: + # For f14+ + cmd = cmd % {'package': RPM_FUSION_URL} + + return cmd +
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/tap.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tap.html new file mode 100644 index 00000000..a49c3306 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tap.html @@ -0,0 +1,710 @@ + + + + + + + + nepi.resources.linux.tap — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.tap

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.resources.linux.node import LinuxNode
    +from nepi.util.timefuncs import tnow, tdiffsec
    +
    +import os
    +import time
    +
    +PYTHON_VSYS_VERSION = "1.0"
    +
    +@clsinit_copy
    +
    [docs]class LinuxTap(LinuxApplication): + _rtype = "linux::Tap" + _help = "Creates a TAP device on a Linux host" + + IFF_TUN = 0x0001 + IFF_TAP = 0x0002 + + @classmethod + def _register_attributes(cls): + ip = Attribute("ip", "IPv4 Address", + flags = Flags.Design) + + mac = Attribute("mac", "MAC Address", + flags = Flags.Design) + + prefix = Attribute("prefix", "IPv4 network prefix", + flags = Flags.Design) + + mtu = Attribute("mtu", "Maximum transmition unit for device", + type = Types.Integer) + + devname = Attribute("deviceName", + "Name of the network interface (e.g. eth0, wlan0, etc)", + flags = Flags.NoWrite) + + up = Attribute("up", "Link up", default=True, + type = Types.Bool) + + pointopoint = Attribute("pointopoint", "Peer IP address", + flags = Flags.Design) + + txqueuelen = Attribute("txqueuelen", "Length of transmission queue", + flags = Flags.Design) + + txqueuelen = Attribute("txqueuelen", "Length of transmission queue", + flags = Flags.Design) + + gre_key = Attribute("greKey", + "GRE key to be used to configure GRE tunnel", + default = "1", + flags = Flags.Design) + + gre_remote = Attribute("greRemote", + "Public IP of remote endpoint for GRE tunnel", + flags = Flags.Design) + + pi = Attribute("pi", "Add PI (protocol information) header", + default = False, + type = Types.Bool) + + tear_down = Attribute("tearDown", + "Bash script to be executed before releasing the resource", + flags = Flags.Design) + + cls._register_attribute(ip) + cls._register_attribute(mac) + cls._register_attribute(prefix) + cls._register_attribute(mtu) + cls._register_attribute(devname) + cls._register_attribute(up) + cls._register_attribute(pointopoint) + cls._register_attribute(txqueuelen) + cls._register_attribute(gre_key) + cls._register_attribute(gre_remote) + cls._register_attribute(pi) + cls._register_attribute(tear_down) + + def __init__(self, ec, guid): + super(LinuxTap, self).__init__(ec, guid) + self._gre_enabled = None + self._vif_prefix = "tap" + self._vif_type = "IFF_TAP" + self._vif_type_flag = LinuxTap.IFF_TAP + self._home = "%s-%s" % (self.vif_prefix, self.guid) + + @property +
    [docs] def node(self): + node = self.get_connected(LinuxNode.get_rtype()) + if node: return node[0] + raise RuntimeError, "linux::TAP/TUN devices must be connected to a linux::Node" +
    + @property +
    [docs] def gre_enabled(self): + if self._gre_enabled is None: + from nepi.resources.linux.gretunnel import LinuxGRETunnel + gre = self.get_connected(LinuxGRETunnel.get_rtype()) + if gre: self._gre_enabled = True + + return self._gre_enabled +
    +
    [docs] def upload_sources(self): + scripts = [] + + # udp-connect python script + udp_connect = os.path.join(os.path.dirname(__file__), "scripts", + "linux-udp-connect.py") + + scripts.append(udp_connect) + + tap_create = os.path.join(os.path.dirname(__file__), "scripts", + "linux-tap-create.py") + + scripts.append(tap_create) + + tap_delete = os.path.join(os.path.dirname(__file__), "scripts", + "linux-tap-delete.py") + + scripts.append(tap_delete) + + # tunnel creation python script + tunchannel = os.path.join(os.path.dirname(__file__), "scripts", + "tunchannel.py") + + scripts.append(tunchannel) + + # Upload scripts + scripts = ";".join(scripts) + + self.node.upload(scripts, + os.path.join(self.node.src_dir), + overwrite = False) + + # upload stop.sh script + stop_command = self.replace_paths(self._stop_command) + + self.node.upload(stop_command, + os.path.join(self.app_home, "stop.sh"), + text = True, + # Overwrite file every time. + # The stop.sh has the path to the socket, which should change + # on every experiment run. + overwrite = True) +
    + def upload_start_command(self): + # If GRE mode is enabled, TAP creation is delayed until the + # tunnel is established + if not self.gre_enabled: + # We want to make sure the device is up and running + # before the deploy is over, so we execute the + # start script now and wait until it finishes. + command = self.get("command") + command = self.replace_paths(command) + + shfile = os.path.join(self.app_home, "start.sh") + self.node.run_and_wait(command, self.run_home, + shfile = shfile, + overwrite = True) + +
    [docs] def upload_start_command(self): + # If GRE mode is enabled, TAP creation is delayed until the + # tunnel is established + if not self.gre_enabled: + # Overwrite file every time. + # The start.sh has the path to the socket, wich should change + # on every experiment run. + command = self.get("command") + + self.info("Uploading command '%s'" % command) + + # replace application specific paths in the command + command = self.replace_paths(command) + + # replace application specific paths in the environment + env = self.get("env") + env = env and self.replace_paths(env) + + shfile = os.path.join(self.app_home, "start.sh") + + self.node.upload_command(command, + shfile = shfile, + env = env, + overwrite = True) + + # We want to make sure the device is up and running + # before the deploy finishes, so we execute now the + # start script. We run it in background, because the + # TAP will live for as long as the process that + # created it is running, and wait until the TAP + # is created. + self._run_in_background() +
    +
    [docs] def do_deploy(self): + if not self.node or self.node.state < ResourceState.PROVISIONED: + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if self.gre_enabled: + self._vif_prefix = "gre" + self._home = "%s-%s" % (self.vif_prefix, self.guid) + + if not self.get("deviceName"): + self.set("deviceName", "%s%d" % (self.vif_prefix, self.guid)) + + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("depends"): + self.set("depends", self._dependencies) + + if not self.get("install"): + self.set("install", self._install) + + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def do_stop(self): + command = self.get('command') or '' + + if self.state == ResourceState.STARTED: + self.info("Stopping command '%s'" % command) + + command = "bash %s" % os.path.join(self.app_home, "stop.sh") + (out, err), proc = self.execute_command(command, + blocking = True) + + if err: + msg = " Failed to stop command '%s' " % command + self.error(msg, out, err) + + self.set_stopped() +
    + @property +
    [docs] def state(self): + state_check_delay = 0.5 + if self._state == ResourceState.STARTED and \ + tdiffsec(tnow(), self._last_state_check) > state_check_delay: + + if self.get("deviceName"): + (out, err), proc = self.node.execute("ifconfig") + + if out.strip().find(self.get("deviceName")) == -1: + # tap is not running is not running (socket not found) + self.set_stopped() + + self._last_state_check = tnow() + + return self._state +
    +
    [docs] def do_release(self): + # Node needs to wait until all associated RMs are released + # to be released + from nepi.resources.linux.tunnel import LinuxTunnel + rms = self.get_connected(LinuxTunnel.get_rtype()) + + for rm in rms: + if rm.state < ResourceState.STOPPED: + self.ec.schedule(self.reschedule_delay, self.release) + return + + super(LinuxTap, self).do_release() +
    +
    [docs] def gre_connect(self, remote_endpoint, connection_app_home, + connection_run_home): + gre_connect_command = self._gre_connect_command(remote_endpoint, + connection_app_home, connection_run_home) + + # upload command to connect.sh script + shfile = os.path.join(connection_app_home, "gre-connect.sh") + self.node.upload_command(gre_connect_command, + shfile = shfile, + overwrite = False) + + # invoke connect script + cmd = "bash %s" % shfile + (out, err), proc = self.node.run(cmd, connection_run_home, + pidfile = "gre_connect_pidfile", + stdout = "gre_connect_stdout", + stderr = "gre_connect_stderr", + ) + + # check if execution errors occurred + msg = " Failed to connect endpoints " + + if proc.poll() or err: + self.error(msg, out, err) + raise RuntimeError, msg + + # Wait for pid file to be generated + pid, ppid = self.node.wait_pid(connection_run_home, + pidfile = "gre_connect_pidfile") + + # If the process is not running, check for error information + # on the remote machine + if not pid or not ppid: + (out, err), proc = self.node.check_errors(connection_run_home, + stderr = "gre_connect_stderr") + + # Out is what was written in the stderr file + if err: + msg = " Failed to start command '%s' " % command + self.error(msg, out, err) + raise RuntimeError, msg + + return True +
    +
    [docs] def initiate_udp_connection(self, remote_endpoint, connection_app_home, + connection_run_home, cipher, cipher_key, bwlimit, txqueuelen): + port = self.udp_connect(remote_endpoint, connection_app_home, + connection_run_home, cipher, cipher_key, bwlimit, txqueuelen) + return port +
    +
    [docs] def udp_connect(self, remote_endpoint, connection_app_home, + connection_run_home, cipher, cipher_key, bwlimit, txqueuelen): + udp_connect_command = self._udp_connect_command( + remote_endpoint, connection_app_home, connection_run_home, + cipher, cipher_key, bwlimit, txqueuelen) + + # upload command to connect.sh script + shfile = os.path.join(connection_app_home, "udp-connect.sh") + self.node.upload_command(udp_connect_command, + shfile = shfile, + overwrite = False) + + # invoke connect script + cmd = "bash %s" % shfile + (out, err), proc = self.node.run(cmd, connection_run_home, + pidfile = "udp_connect_pidfile", + stdout = "udp_connect_stdout", + stderr = "udp_connect_stderr", + ) + + # check if execution errors occurred + msg = "Failed to connect endpoints " + + if proc.poll(): + self.error(msg, out, err) + raise RuntimeError, msg + + # Wait for pid file to be generated + self._pid, self._ppid = self.node.wait_pid( + connection_run_home, + pidfile = "udp_connect_pidfile") + + # If the process is not running, check for error information + # on the remote machine + if not self._pid or not self._ppid: + (out, err), proc = self.node.check_errors( + connection_run_home, + stderr = "udp_connect_stderr") + + # Out is what was written in the stderr file + if err: + msg = " Failed to start command '%s' " % command + self.error(msg, out, err) + raise RuntimeError, msg + + return self.wait_file(connection_run_home, "local_port") +
    +
    [docs] def establish_udp_connection(self, remote_endpoint, + connection_app_home, connection_run_home, port): + # upload remote port number to file + rem_port = "%s\n" % port + self.node.upload(rem_port, + os.path.join(connection_run_home, "remote_port"), + text = True, + overwrite = False) +
    +
    [docs] def verify_connection(self, remote_endpoint, + connection_app_home, connection_run_home): + + return self.wait_file(connection_run_home, "ret_file") +
    +
    [docs] def terminate_connection(self, remote_endpoint, + connection_app_home, connection_run_home): + if self._pid and self._ppid: + (out, err), proc = self.node.kill(self._pid, self._ppid, + sudo = True) + + # check if execution errors occurred + if proc.poll() and err: + msg = " Failed to Kill the Tap" + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def check_status(self): + return self.node.status(self._pid, self._ppid) +
    +
    [docs] def wait_file(self, home, filename): + """ Waits until file on endpoint is generated """ + result = None + delay = 1.0 + + for i in xrange(20): + (out, err), proc = self.node.check_output(home, filename) + if out: + result = out.strip() + break + else: + time.sleep(delay) + delay = delay * 1.5 + else: + msg = "Couldn't retrieve %s" % filename + self.error(msg, out, err) + raise RuntimeError, msg + + return result +
    + @property + def _start_command(self): + if self.gre_enabled: + command = [] + else: + command = ["sudo -S "] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/linux-tap-create.py") + command.append("-t %s" % self.vif_type) + command.append("-a %s" % self.get("ip")) + command.append("-n %s" % self.get("prefix")) + command.append("-N %s " % self.get("deviceName")) + command.append("-S %s " % self.sock_name) + if self.get("pi"): + command.append("-p") + + return " ".join(command) + + @property + def _stop_command(self): + if self.gre_enabled: + command = self._stop_gre_command + else: + command = ["sudo -S "] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/linux-tap-delete.py") + command.append("-N %s " % self.get("deviceName")) + command.append("-S %s " % self.sock_name) + command = " ".join(command) + + return command + + def _gre_connect_command(self, remote_endpoint, + connection_app_home, connecrion_app_home): + # Set the remote endpoint to (private) device IP + self.set("pointopoint", remote_endpoint.get("ip")) + ## public node IP + self.set("greRemote", remote_endpoint.node.get("ip")) + + # Generate GRE connect command + command = ["("] + command.append(self._stop_gre_command) + command.append(") ; (") + command.append(self._start_gre_command) + command.append(")") + + command = " ".join(command) + command = self.replace_paths(command) + + return command + + @property + def _start_gre_command(self): + command = [] + command.append("sudo -S modprobe ip_gre") + command.append("sudo -S ip tunnel add %s mode gre remote %s local %s ttl 255 csum key %s" % ( + self.get("deviceName"), + self.get("greRemote"), + self.node.get("ip"), + self.get("greKey") + )) + command.append("sudo -S ip addr add %s/%s peer %s/%s dev %s" % ( + self.get("ip"), + self.get("prefix"), + self.get("pointopoint"), + self.get("prefix"), + self.get("deviceName"), + )) + command.append("sudo -S ip link set %s up " % self.get("deviceName")) + + return ";".join(command) + + @property + def _stop_gre_command(self): + command = [] + command.append("sudo -S modprobe -r ip_gre") + command.append("sudo -S ip link set down dev %s" % ( + self.get("deviceName"), + )) + command.append("sudo -S ip link del dev %s" % ( + self.get("deviceName"), + )) + + return ";".join(command) + + def _udp_connect_command(self, remote_endpoint, + connection_app_home, connection_run_home, + cipher, cipher_key, bwlimit, txqueuelen): + + # Set the remote endpoint to the IP of the device + self.set("pointopoint", remote_endpoint.get("ip")) + + # Public IP of the remote NODE to stablish tunnel + remote_ip = remote_endpoint.node.get("ip") + local_ip = self.node.get("ip") + + local_port_file = os.path.join(connection_run_home, + "local_port") + + remote_port_file = os.path.join(connection_run_home, + "remote_port") + + ret_file = os.path.join(connection_run_home, + "ret_file") + + # Generate UDP connect command + # Use the start command to configure TAP with peer info + start_command = self._start_command + + command = [""] + # Use pl-vid-udp-connect.py to stablish the tunnel between endpoints + command.append("sudo -S") + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/linux-udp-connect.py") + command.append("-t %s" % self.vif_type) + command.append("-S %s " % self.sock_name) + command.append("-p %s " % local_port_file) + command.append("-P %s " % remote_port_file) + command.append("-o %s " % local_ip) + command.append("-O %s " % remote_ip) + command.append("-R %s " % ret_file) + if self.get("pi"): + command.append("-n") + if cipher: + command.append("-c %s " % cipher) + if cipher_key: + command.append("-k %s " % cipher_key) + if txqueuelen: + command.append("-q %s " % txqueuelen) + if bwlimit: + command.append("-b %s " % bwlimit) + + command = " ".join(command) + command = self.replace_paths(command) + + return command + + @property + def _dependencies(self): + return "mercurial make gcc" + + @property + def _install(self): + # Install python-vsys and python-passfd + install_passfd = ( " ( python -c 'import passfd' ) " + " || " + " ( " + " cd ${SRC} ; " + " hg clone http://nepi.inria.fr/code/python-passfd ; " + " cd python-passfd ; " + " make all ; " + " sudo -S make install " + " )" ) + + return install_passfd + + def valid_connection(self, guid): + # TODO: Validate! + return True + + @property +
    [docs] def vif_type(self): + return self._vif_type +
    + @property +
    [docs] def vif_type_flag(self): + return self._vif_type_flag +
    + @property +
    [docs] def vif_prefix(self): + return self._vif_prefix +
    + @property +
    [docs] def sock_name(self): + return os.path.join(self.run_home, "%s.sock" % self.vif_prefix) +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/tcpdump.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tcpdump.html new file mode 100644 index 00000000..690d4808 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tcpdump.html @@ -0,0 +1,499 @@ + + + + + + + + nepi.resources.linux.tcpdump — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.tcpdump

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy 
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.util.timefuncs import tnow
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxTcpdump(LinuxApplication): + _rtype = "linux::Tcpdump" + + @classmethod + def _register_attributes(cls): + A = Attribute("A", + "Sets tcpdump -A option. " + "Prints each packet (minus its link level header) in ASCII.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + b = Attribute("b", + "Sets tcpdump -b option. " + "Prints the AS number in BGP packets in ASDOT notation. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + B = Attribute("B", + "Sets tcpdump -B option. " + "Sets the operaing system capture buffer size in untils of " + "KiB (1024 bytes).", + flags = Flags.Design) + + c = Attribute("c", + "Sets tcpdump -c option. " + "Exists after receiving count packets.", + flags = Flags.Design) + + C = Attribute("C", + "Sets tcpdump -C option. " + "Before writing a raw packet to a savefile, check whether the " + "file is currently larger than file_size and, if so, close the " + "current savefile and open a new one. " + "Savefiles after the first savefile will have the name specified " + "with the -w with a number after it, starting at 1 and continuing " + "upward. ", + flags = Flags.Design) + + d = Attribute("d", + "Sets tcpdump -d option. " + "Dump the compiled packet-matching code in a human readable form " + "to standard output and stop.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + dd = Attribute("dd", + "Sets tcpdump -dd option. " + "Dump packet-matching code as a C program fragment. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + ddd = Attribute("ddd", + "Sets tcpdump -ddd option. " + "Dump packet-matching code as decimal numbers " + "(preceded with a count).", + type = Types.Bool, + default = False, + flags = Flags.Design) + + D = Attribute("D", + "Sets tcpdump -D option. " + "Print the list of the network interfaces available on the system " + "and on which tcpdump can capture packets. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + e = Attribute("e", + "Sets tcpdump -e option. " + "Print the link-level header on each dump line.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + F = Attribute("F", + "Sets tcpdump -F option. " + "Use file as input for the filter expression.", + flags = Flags.Design) + + G = Attribute("G", + "Sets tcpdump -G option. " + "If specified, rotates the dump file specified with the -w " + "option every rotate_seconds seconds. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + i = Attribute("i", + "Sets tcpdump -i option. " + "Listen on interface. If unspecified, tcpdump searches the " + "system interface list for the lowest numbered, configured " + "up interface (excluding loopback). ", + flags = Flags.Design) + + I = Attribute("I", + "Sets tcpdump -I option. " + "Put the interface in 'monitor mode'; this is supported only " + "on IEEE 802.11 Wi-Fi interfaces, and supported only on some " + "operating systems. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + j = Attribute("j", + "Sets tcpdump -j option. " + "Sets the time stamp type for the capture to tstamp_type. " + "The names to use for the time stamp types are given in " + "pcap-tstamp-type(7); not all the types listed there will " + "necessarily be valid for any given interface.", + flags = Flags.Design) + + K = Attribute("K", + "Sets tcpdump -K option. " + "Don't attempt to verify IP, TCP, or UDP checksums. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + l = Attribute("l", + "Sets tcpdump -l option. " + "Make stdout line buffered. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + U = Attribute("U", + "Sets tcpdump -U option. " + "Similar to -l in its behavior, but it will cause output to be " + "``packet-buffered'', so that the output is written to stdout " + "at the end of each packet. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + n = Attribute("n", + "Sets tcpdump -n option. " + "Don't convert addresses (i.e., host addresses, port numbers, " + "etc.) to names.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + N = Attribute("N", + "Sets tcpdump -N option. " + "Don't print domain name qualification of host names. " + "E.g., if you give this flag then tcpdump will print ``nic'' " + "instead of ``nic.ddn.mil''.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + S = Attribute("S", + "Sets tcpdump -S option. " + "Print absolute, rather than relative, TCP sequence numbers.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + s = Attribute("s", + "Sets tcpdump -s option. " + "Snarf snaplen bytes of data from each packet rather than " + "the default of 65535 bytes. ", + flags = Flags.Design) + + T = Attribute("T", + "Sets tcpdump -T option. " + "Force packets selected by 'expression' to be interpreted the " + "specified type. Currently known types are aodv (Ad-hoc " + "On-demand Distance Vector protocol), cnfp (Cisco NetFlow " + "protocol), rpc (Remote Procedure Call), rtp (Real-Time " + "Applications protocol), rtcp (Real-Time Applications control " + "protocol), snmp (Simple Network Management Protocol), tftp " + "(Trivial File Transfer Protocol), vat (Visual Audio Tool), " + "and wb (distributed White Board).", + flags = Flags.Design) + + t = Attribute("t", + "Sets tcpdump -t option. " + "Don't print a timestamp on each dump line.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + tt = Attribute("tt", + "Sets tcpdump -tt option. " + "Print an unformatted timestamp on each dump line. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + ttt = Attribute("ttt", + "Sets tcpdump -ttt option. " + "Print a delta (micro-second resolution) between current " + "and previous line on each dump line.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + tttt = Attribute("tttt", + "Sets tcpdump -tttt option. " + "Print a timestamp in default format proceeded by date on " + "each dump line. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + ttttt = Attribute("ttttt", + "Sets tcpdump -ttttt option. " + "Print a delta (micro-second resolution) between current and " + "first line on each dump line.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + v = Attribute("v", + "Sets tcpdump -v option. " + "When parsing and printing, produce (slightly more) " + "verbose output. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + vv = Attribute("vv", + "Sets tcpdump -vv option. " + "Even more verbose output. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + vvv = Attribute("vvv", + "Sets tcpdump -vv option. " + "Even more verbose output. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + w = Attribute("w", + "Sets tcpdump -w option. " + "Write the raw packets to file rather than parsing " + "and printing them out.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + expression = Attribute("expression", + "selects which packets will be dumped.", + flags = Flags.Design) + + cls._register_attribute(A) + cls._register_attribute(b) + cls._register_attribute(B) + cls._register_attribute(c) + cls._register_attribute(C) + cls._register_attribute(d) + cls._register_attribute(dd) + cls._register_attribute(ddd) + cls._register_attribute(D) + cls._register_attribute(e) + cls._register_attribute(F) + cls._register_attribute(G) + cls._register_attribute(i) + cls._register_attribute(I) + cls._register_attribute(j) + cls._register_attribute(K) + cls._register_attribute(l) + cls._register_attribute(U) + cls._register_attribute(n) + cls._register_attribute(N) + cls._register_attribute(S) + cls._register_attribute(s) + cls._register_attribute(T) + cls._register_attribute(t) + cls._register_attribute(tt) + cls._register_attribute(ttt) + cls._register_attribute(tttt) + cls._register_attribute(ttttt) + cls._register_attribute(v) + cls._register_attribute(vv) + cls._register_attribute(vvv) + cls._register_attribute(w) + cls._register_attribute(expression) + + def __init__(self, ec, guid): + super(LinuxTcpdump, self).__init__(ec, guid) + self._home = "tcpdump-%s" % self.guid + self._sudo_kill = True + +
    [docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("env"): + self.set("env", "PATH=$PATH:/usr/sbin/") + + if not self.get("depends"): + self.set("depends", "tcpdump") + + super(LinuxTcpdump, self).do_deploy() +
    + @property + def _start_command(self): + args = [] + args.append("sudo -S tcpdump") + if self.get("A") == True: + args.append("-A") + if self.get("b") == True: + args.append("-b") + if self.get("B"): + args.append("-B %s" % self.get("B")) + if self.get("c"): + args.append("-c %s" % self.get("c")) + if self.get("C"): + args.append("-C %s" % self.get("C")) + if self.get("d") == True: + args.append("-d") + if self.get("dd") == True: + args.append("-dd") + if self.get("ddd") == True: + args.append("-ddd") + if self.get("D") == True: + args.append("-D") + if self.get("e") == True: + args.append("-e") + if self.get("F"): + args.append("-F %s" % self.get("F")) + if self.get("G") == True: + args.append("-G") + if self.get("i"): + args.append("-i %s" % self.get("i")) + if self.get("I") == True: + args.append("-I") + if self.get("j"): + args.append("-j %s" % self.get("j")) + if self.get("K") == True: + args.append("-K") + if self.get("l") == True: + args.append("-l") + if self.get("U") == True: + args.append("-U") + if self.get("n") == True: + args.append("-n") + if self.get("N") == True: + args.append("-N") + if self.get("S") == True: + args.append("-S") + if self.get("s"): + args.append("-s %s" % self.get("s")) + if self.get("T"): + args.append("-T %s" % self.get("T")) + if self.get("t") == True: + args.append("-t") + if self.get("tt") == True: + args.append("-tt") + if self.get("ttt") == True: + args.append("-ttt") + if self.get("tttt") == True: + args.append("-tttt") + if self.get("ttttt") == True: + args.append("-ttttt") + if self.get("v") == True: + args.append("-v") + if self.get("vv") == True: + args.append("-vv") + if self.get("vvv") == True: + args.append("-vvv") + if self.get("w"): + args.append("-w %s" % self.get("w")) + if self.get("expression"): + args.append(self.get("expression")) + + command = " ".join(args) + + return command + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/traceroute.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/traceroute.html new file mode 100644 index 00000000..21c71a3d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/traceroute.html @@ -0,0 +1,217 @@ + + + + + + + + nepi.resources.linux.traceroute — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.traceroute

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState 
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.util.timefuncs import tnow
    +
    +import os
    +import socket
    +
    +@clsinit_copy
    +
    [docs]class LinuxTraceroute(LinuxApplication): + _rtype = "linux::Traceroute" + + @classmethod + def _register_attributes(cls): + countinuous = Attribute("continuous", + "Run traceroute in a while loop", + type = Types.Bool, + default = False, + flags = Flags.Design) + + print_timestamp = Attribute("printTimestamp", + "Print timestamp before running traceroute", + type = Types.Bool, + default = False, + flags = Flags.Design) + + use_ip = Attribute("useIP", + "Use the IP address instead of the host domain name. " + "Useful for environments were dns resolution problems occur " + "frequently", + type = Types.Bool, + default = False, + flags = Flags.Design) + + target = Attribute("target", + "Traceroute target host (host that will be pinged)", + flags = Flags.Design) + + early_start = Attribute("earlyStart", + "Start ping as early as deployment. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + cls._register_attribute(countinuous) + cls._register_attribute(print_timestamp) + cls._register_attribute(use_ip) + cls._register_attribute(target) + cls._register_attribute(early_start) + + def __init__(self, ec, guid): + super(LinuxTraceroute, self).__init__(ec, guid) + self._home = "traceroute-%s" % self.guid + +
    [docs] def upload_start_command(self): + super(LinuxTraceroute, self).upload_start_command() + + if self.get("earlyStart") == True: + self._run_in_background() +
    +
    [docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("depends"): + self.set("depends", "traceroute") + + super(LinuxTraceroute, self).do_deploy() +
    +
    [docs] def do_start(self): + if self.get("earlyStart") == True: + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg + else: + super(LinuxTraceroute, self).do_start() +
    + @property + def _start_command(self): + args = [] + if self.get("continuous") == True: + args.append("while true; do ") + if self.get("printTimestamp") == True: + args.append("""echo "`date +'%Y%m%d%H%M%S'`";""") + args.append("traceroute") + + target = self.get("target") + if self.get("useIP") == True: + target = socket.gethostbyname(target) + args.append(target) + + if self.get("continuous") == True: + args.append("; sleep 2 ; done ") + + command = " ".join(args) + + return command + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/tun.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tun.html new file mode 100644 index 00000000..f93671e8 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tun.html @@ -0,0 +1,127 @@ + + + + + + + + nepi.resources.linux.tun — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.tun

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.linux.tap import LinuxTap
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxTun(LinuxTap): + _rtype = "linux::Tun" + _help = "Creates a TUN device on a Linux host" + + def __init__(self, ec, guid): + super(LinuxTun, self).__init__(ec, guid) + self._vif_prefix = "tun" + self._vif_type = "IFF_TUN" + self._vif_type_flag = LinuxTap.IFF_TUN + self._home = "%s-%s" % (self.vif_prefix, self.guid) + +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/tunnel.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tunnel.html new file mode 100644 index 00000000..6efeb748 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tunnel.html @@ -0,0 +1,256 @@ + + + + + + + + nepi.resources.linux.tunnel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.tunnel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.util.timefuncs import tnow, tdiffsec
    +
    +import os
    +import time
    +
    +state_check_delay = 0.5
    +
    +@clsinit_copy
    +
    [docs]class LinuxTunnel(LinuxApplication): + _rtype = "abstract::linux::Tunnel" + _help = "Constructs a tunnel between two Linux endpoints" + + def __init__(self, ec, guid): + super(LinuxTunnel, self).__init__(ec, guid) + self._home = "tunnel-%s" % self.guid + +
    [docs] def log_message(self, msg): + return " guid %d - tunnel %s - %s - %s " % (self.guid, + self.endpoint1.node.get("hostname"), + self.endpoint2.node.get("hostname"), + msg) +
    +
    [docs] def get_endpoints(self): + """ Returns the list of RM that are endpoints to the tunnel + """ + raise NotImplementedError +
    + @property +
    [docs] def endpoint1(self): + endpoints = self.get_endpoints() + if endpoints: return endpoints[0] + return None +
    + @property +
    [docs] def endpoint2(self): + endpoints = self.get_endpoints() + if endpoints and len(endpoints) > 1: return endpoints[1] + return None +
    +
    [docs] def app_home(self, endpoint): + return os.path.join(endpoint.node.exp_home, self._home) +
    +
    [docs] def run_home(self, endpoint): + return os.path.join(self.app_home(endpoint), self.ec.run_id) +
    +
    [docs] def endpoint_mkdir(self, endpoint): + endpoint.node.mkdir(self.run_home(endpoint)) +
    +
    [docs] def initiate_connection(self, endpoint, remote_endpoint): + raise NotImplementedError +
    +
    [docs] def establish_connection(self, endpoint, remote_endpoint, data): + raise NotImplementedError +
    +
    [docs] def verify_connection(self, endpoint, remote_endpoint): + raise NotImplementedError +
    +
    [docs] def terminate_connection(self, endpoint, remote_endpoint): + raise NotImplementedError +
    +
    [docs] def check_state_connection(self, endpoint, remote_endpoint): + raise NotImplementedError +
    +
    [docs] def do_provision(self): + # create run dir for tunnel on each node + self.endpoint_mkdir(self.endpoint1) + self.endpoint_mkdir(self.endpoint2) + + self.debug("Initiate the connection") + # Start 2 step connection + # Initiate connection from endpoint 1 to endpoint 2 + data1 = self.initiate_connection(self.endpoint1, self.endpoint2) + + # Initiate connection from endpoint 2 to endpoint 1 + data2 = self.initiate_connection(self.endpoint2, self.endpoint1) + + self.debug("Establish the connection") + # Establish connection from endpoint 1 to endpoint 2 + self.establish_connection(self.endpoint1, self.endpoint2, data2) + + # Establish connection from endpoint 2 to endpoint 1 + self.establish_connection(self.endpoint2, self.endpoint1, data1) + + self.debug("Verify the connection") + # check if connection was successful on both sides + self.verify_connection(self.endpoint1, self.endpoint2) + self.verify_connection(self.endpoint2, self.endpoint1) + + self.info("Provisioning finished") + + self.set_provisioned() +
    +
    [docs] def do_deploy(self): + if (not self.endpoint1 or self.endpoint1.state < ResourceState.READY) or \ + (not self.endpoint2 or self.endpoint2.state < ResourceState.READY): + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def do_stop(self): + """ Stops application execution + """ + + if self.state == ResourceState.STARTED: + self.info("Stopping tunnel") + + self.terminate_connection(self.endpoint1, self.endpoint2) + self.terminate_connection(self.endpoint2, self.endpoint1) + + self.set_stopped() +
    + @property +
    [docs] def state(self): + """ Returns the state of the application + """ + if self._state == ResourceState.STARTED: + # In order to avoid overwhelming the remote host and + # the local processor with too many ssh queries, the state is only + # requested every 'state_check_delay' seconds. + if tdiffsec(tnow(), self._last_state_check) > state_check_delay: + + self.check_state_connection() + + self._last_state_check = tnow() + + return self._state +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/udptest.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/udptest.html new file mode 100644 index 00000000..a896201e --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/udptest.html @@ -0,0 +1,461 @@ + + + + + + + + nepi.resources.linux.udptest — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.udptest

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.util.timefuncs import tnow
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class LinuxUdpTest(LinuxApplication): + """ Uses the hpcbench udptest tool to gather UDP measurements. + Measurements require two ends, a server and a client RM. + + http://hpcbench.sourceforge.net/ + """ + _rtype = "linux::UdpTest" + + @classmethod + def _register_attributes(cls): + s = Attribute("s", + "Runs in server mode. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + p = Attribute("p", + "Port to listen to in server mode, or to connect to in client mode. " + "Defaults to 5678. ", + type = Types.Integer, + flags = Flags.Design) + + a = Attribute("a", + "Client option. Perform UDP Round Trip Time (latency) ", + type = Types.Bool, + flags = Flags.Design) + + A = Attribute("A", + "Client option. " + "Message size for UDP RTT test. " + "UDP RTT (latency) test with specified message size.", + type = Types.Integer, + flags = Flags.Design) + + b = Attribute("b", + "Client option. " + "Client UDP buffer size in bytes. Using system default " + "value if not defined.", + type = Types.Integer, + flags = Flags.Design) + + B = Attribute("B", + "Client option. " + "Server UDP buffer size in bytes. The same as cleint's by default.", + type = Types.Integer, + flags = Flags.Design) + + c = Attribute("c", + "Client option. " + "CPU log option. Tracing system info during the test. " + "Only available when output is defined. ", + type = Types.Bool, + flags = Flags.Design) + + d = Attribute("d", + "Client option. " + "Data size of each read/write in bytes. The same as packet size " + "by default.", + type = Types.Integer, + flags = Flags.Design) + + e = Attribute("e", + "Client option. " + "Exponential test (data size of each sending increasing from 1 " + "byte to packet size). ", + type = Types.Bool, + flags = Flags.Design) + + g = Attribute("g", + "Client option. " + "UDP traffic generator (Keep sending data to a host). " + "Work without server's support.", + type = Types.Bool, + flags = Flags.Design) + + target = Attribute("target", + "Client option. " + "Hostname or IP address of UDP server. Must be specified.", + flags = Flags.Design) + + i = Attribute("i", + "Client option. " + "Bidirectional UDP throuhgput test. Default is unidirection " + "stream test. ", + type = Types.Bool, + flags = Flags.Design) + + l = Attribute("l", + "Client option. " + "UDP datagram (packet) size in bytes ( < udp-buffer-szie ). " + "1460 by default.", + type = Types.Integer, + flags = Flags.Design) + + m = Attribute("m", + "Client option. " + "Total message size in bytes. 1048576 by default.", + type = Types.Integer, + flags = Flags.Design) + + o = Attribute("o", + "Client option. " + "Output file name. ", + flags = Flags.Design) + + P = Attribute("P", + "Client option. " + "Write the plot file for gnuplot. Only enable when the output " + "is specified. ", + type = Types.Bool, + flags = Flags.Design) + + q = Attribute("q", + "Client option. " + "Define the TOS field of IP packets. " + "Six values can be used for this setting:\n" + " 1:(IPTOS)-Minimize delay\n" + " 2:(IPTOS)-Maximize throughput\n" + " 3:(DiffServ)-Class1 with low drop probability\n" + " 4:(DiffServ)-class1 with high drop probability\n" + " 5:(DiffServ)-Class4 with low drop probabiltiy\n" + " 6:(DiffServ)-Class4 with high drop probabiltiy\n" + "Write the plot file for gnuplot. Only enable when the output " + "is specified. ", + type = Types.Enumerate, + allowed = ["1", "2", "3", "4", "5", "6"], + flags = Flags.Design) + + r = Attribute("r", + "Client option. " + "Repetition of tests. 10 by default. ", + type = Types.Integer, + flags = Flags.Design) + + t = Attribute("t", + "Client option. " + "Test time constraint in seconds. 5 by default. ", + type = Types.Integer, + flags = Flags.Design) + + T = Attribute("T", + "Client option. " + "Throughput constraint for UDP generator or throughput " + "test. Unlimited by default. ", + type = Types.Integer, + flags = Flags.Design) + + continuous = Attribute("continuous", + "Run nping in a while loop", + type = Types.Bool, + default = False, + flags = Flags.Design) + + print_timestamp = Attribute("printTimestamp", + "Print timestamp before running nping", + type = Types.Bool, + default = False, + flags = Flags.Design) + + cls._register_attribute(s) + cls._register_attribute(p) + cls._register_attribute(a) + cls._register_attribute(A) + cls._register_attribute(b) + cls._register_attribute(B) + cls._register_attribute(c) + cls._register_attribute(d) + cls._register_attribute(e) + cls._register_attribute(g) + cls._register_attribute(target) + cls._register_attribute(g) + cls._register_attribute(i) + cls._register_attribute(l) + cls._register_attribute(m) + cls._register_attribute(o) + cls._register_attribute(P) + cls._register_attribute(q) + cls._register_attribute(r) + cls._register_attribute(t) + cls._register_attribute(T) + cls._register_attribute(continuous) + cls._register_attribute(print_timestamp) + + def __init__(self, ec, guid): + super(LinuxUdpTest, self).__init__(ec, guid) + self._home = "udptest-%s" % self.guid + +
    [docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("sources"): + self.set("sources", self._sources) + + if not self.get("install"): + self.set("install", self._install) + + if not self.get("build"): + self.set("build", self._build) + + if not self.get("env"): + self.set("env", self._environment) + + if not self.get("depends"): + self.set("depends", self._depends) + + super(LinuxUdpTest, self).do_deploy() +
    +
    [docs] def upload_start_command(self): + super(LinuxUdpTest, self).upload_start_command() + + if self.get("s") == True: + # We want to make sure the server is running + # before the client starts. + # Run the command as a bash script in background, + # in the host ( but wait until the command has + # finished to continue ) + self._run_in_background() +
    +
    [docs] def do_start(self): + if self.get("s") == True: + # Server is already running + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, err + else: + super(LinuxUdpTest, self).do_start() +
    + @property + def _start_command(self): + args = [] + if self.get("continuous") == True: + args.append("while true; do ") + + if self.get("printTimestamp") == True: + args.append("""echo "`date +'%Y%m%d%H%M%S'`";""") + + if self.get("s") == True: + args.append("udpserver") + else: + args.append("udptest") + + if self.get("p"): + args.append("-p %d" % self.get("p")) + if self.get("a") == True: + args.append("-a") + if self.get("A"): + args.append("-A %d" % self.get("A")) + if self.get("b"): + args.append("-b %d" % self.get("b")) + if self.get("B"): + args.append("-B %d" % self.get("B")) + if self.get("c") == True: + args.append("-c") + if self.get("d"): + args.append("-d %d" % self.get("d")) + if self.get("e") == True: + args.append("-e") + if self.get("g") == True: + args.append("-g") + if self.get("target"): + args.append("-h %s" % self.get("target")) + if self.get("i") == True: + args.append("-i") + if self.get("l"): + args.append("-l %d" % self.get("l")) + if self.get("m"): + args.append("-m %d" % self.get("m")) + if self.get("o"): + args.append("-o %d" % self.get("o")) + if self.get("P"): + args.append("-P %d" % self.get("P")) + if self.get("q"): + args.append("-q %s" % self.get("q")) + if self.get("r"): + args.append("-r %d" % self.get("r")) + if self.get("t"): + args.append("-t %d" % self.get("t")) + if self.get("T"): + args.append("-T %d" % self.get("T")) + + if self.get("continuous") == True: + args.append("; done ") + + command = " ".join(args) + + return command + + @property + def _sources(self): + return "http://hpcbench.sourceforge.net/udp.tar.gz" + + @property + def _depends(self): + return "gcc make" + + @property + def _build(self): + sources = self.get("sources").split(" ")[0] + sources = os.path.basename(sources) + + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN}/udptest && " + " echo 'binaries found, nothing to do' " + " ) || ( " + # If not, untar and build + " ( " + " mkdir -p ${SRC}/udptest && " + " tar xf ${SRC}/%(sources)s --strip-components=1 -C ${SRC}/udptest " + " ) && " + "cd ${SRC}/udptest && " + # Just execute and silence warnings... + " ( make ) " + " )") % ({ 'sources': sources, + }) + + @property + def _install(self): + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN}/udptest && " + " echo 'binaries found, nothing to do' " + " ) || ( " + # If not, install + " mv ${SRC}/udptest ${BIN} " + " )") + + @property + def _environment(self): + return "PATH=$PATH:${BIN}/udptest" + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/udptunnel.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/udptunnel.html new file mode 100644 index 00000000..38d28359 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/udptunnel.html @@ -0,0 +1,245 @@ + + + + + + + + nepi.resources.linux.udptunnel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.linux.udptunnel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.tunnel import LinuxTunnel
    +from nepi.util.sshfuncs import ProcStatus
    +from nepi.util.timefuncs import tnow, tdiffsec
    +
    +import os
    +import socket
    +import time
    +
    +@clsinit_copy
    +
    [docs]class LinuxUdpTunnel(LinuxTunnel): + _rtype = "linux::UdpTunnel" + _help = "Constructs a tunnel between two Linux endpoints using a UDP connection " + _platform = "linux" + + @classmethod + def _register_attributes(cls): + cipher = Attribute("cipher", + "Cipher to encript communication. " + "One of PLAIN, AES, Blowfish, DES, DES3. ", + default = None, + allowed = ["PLAIN", "AES", "Blowfish", "DES", "DES3"], + type = Types.Enumerate, + flags = Flags.Design) + + cipher_key = Attribute("cipherKey", + "Specify a symmetric encryption key with which to protect " + "packets across the tunnel. python-crypto must be installed " + "on the system." , + flags = Flags.Design) + + txqueuelen = Attribute("txQueueLen", + "Specifies the interface's transmission queue length. " + "Defaults to 1000. ", + type = Types.Integer, + flags = Flags.Design) + + bwlimit = Attribute("bwLimit", + "Specifies the interface's emulated bandwidth in bytes " + "per second.", + type = Types.Integer, + flags = Flags.Design) + + cls._register_attribute(cipher) + cls._register_attribute(cipher_key) + cls._register_attribute(txqueuelen) + cls._register_attribute(bwlimit) + + def __init__(self, ec, guid): + super(LinuxUdpTunnel, self).__init__(ec, guid) + self._home = "udp-tunnel-%s" % self.guid + self._pids = dict() + +
    [docs] def log_message(self, msg): + return " guid %d - udptunnel %s - %s - %s " % (self.guid, + self.endpoint1.node.get("hostname"), + self.endpoint2.node.get("hostname"), + msg) +
    +
    [docs] def get_endpoints(self): + """ Returns the list of RM that are endpoints to the tunnel + """ + connected = [] + for guid in self.connections: + rm = self.ec.get_resource(guid) + if hasattr(rm, "initiate_udp_connection"): + connected.append(rm) + return connected +
    +
    [docs] def initiate_connection(self, endpoint, remote_endpoint): + cipher = self.get("cipher") + cipher_key = self.get("cipherKey") + bwlimit = self.get("bwLimit") + txqueuelen = self.get("txQueueLen") + connection_app_home = self.app_home(endpoint) + connection_run_home = self.run_home(endpoint) + + port = endpoint.initiate_udp_connection( + remote_endpoint, + connection_app_home, + connection_run_home, + cipher, cipher_key, bwlimit, txqueuelen) + + return port +
    +
    [docs] def establish_connection(self, endpoint, remote_endpoint, port): + connection_app_home = self.app_home(endpoint) + connection_run_home = self.run_home(endpoint) + + endpoint.establish_udp_connection(remote_endpoint, + connection_app_home, + connection_run_home, + port) +
    +
    [docs] def verify_connection(self, endpoint, remote_endpoint): + connection_app_home = self.app_home(endpoint) + connection_run_home = self.run_home(endpoint) + + endpoint.verify_connection(remote_endpoint, + connection_app_home, + connection_run_home) +
    +
    [docs] def terminate_connection(self, endpoint, remote_endpoint): + connection_app_home = self.app_home(endpoint) + connection_run_home = self.run_home(endpoint) + + endpoint.terminate_connection(remote_endpoint, + connection_app_home, + connection_run_home) +
    +
    [docs] def check_state_connection(self): + # Make sure the process is still running in background + # No execution errors occurred. Make sure the background + # process with the recorded pid is still running. + + status1 = self.endpoint1.check_status() + status2 = self.endpoint2.check_status() + + if status1 == ProcStatus.FINISHED and \ + status2 == ProcStatus.FINISHED: + + # check if execution errors occurred + (out1, err1), proc1 = self.endpoint1.node.check_errors( + self.run_home(self.endpoint1)) + + (out2, err2), proc2 = self.endpoint2.node.check_errors( + self.run_home(self.endpoint2)) + + if err1 or err2: + msg = "Error occurred in tunnel" + self.error(msg, err1, err2) + self.fail() + else: + self.set_stopped() +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsapplication.html new file mode 100644 index 00000000..40d168ee --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsapplication.html @@ -0,0 +1,190 @@ + + + + + + + + nepi.resources.netns.netnsapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnsapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.resources.netns.netnsbase import NetNSBase
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +
    +import shlex
    +
    +@clsinit_copy
    +
    [docs]class NetNSApplication(NetNSBase): + _rtype = "netns::Application" + + def __init__(self, ec, guid): + super(NetNSApplication, self).__init__(ec, guid) + self._traces = dict() + + @classmethod + def _register_attributes(cls): + command = Attribute("command", "Command to execute", flags=Flags.Design) + cls._register_attribute(command) + + @property +
    [docs] def emulation(self): + return self.node.emulation +
    + @property +
    [docs] def node(self): + from nepi.resources.netns.netnsnode import NetNSNode + node = self.get_connected(NetNSNode.get_rtype()) + + if not node: + msg = "Route not connected to Node!!" + self.error(msg) + raise RuntimeError, msg + + return node[0] +
    + @property + def _rms_to_wait(self): + return [self.node] + +
    [docs] def do_start(self): + if self.emulation.state < ResourceState.STARTED: + self.debug("---- RESCHEDULING START ----" ) + self.ec.schedule(self.reschedule_delay, self.start) + else: + self._configure_traces() + + command = shlex.split(self.get("command")) + stdout = self._traces["stdout"] + stderr = self._traces["stderr"] + self._uuid = self.emulation.invoke(self.node.uuid, + "Popen", command, stdout = stdout, + stderr = stderr) + + super(NetNSApplication, self).do_start() + self._start_time = self.emulation.start_time +
    + def _configure_traces(self): + stdout = "%s/%d.stdout" % (self.emulation.run_home, self.guid) + stderr = "%s/%d.stderr" % (self.emulation.run_home, self.guid) + self._trace_filename["stdout"] = stdout + self._trace_filename["stderr"] = stderr + self._traces["stdout"] = self.emulation.create("open", stdout, "w") + self._traces["stderr"] = self.emulation.create("open", stderr, "w") + + @property +
    [docs] def state(self): + if self._state == ResourceState.STARTED: + retcode = self.emulation.invoke(self.uuid, "poll") + + if retcode is not None: + if retcode == 0: + self.set_stopped() + else: + out = "" + msg = " Failed to execute command '%s'" % self.get("command") + err = self.trace("stderr") + self.error(msg, out, err) + self.do_fail() + + return self._state +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsbase.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsbase.html new file mode 100644 index 00000000..575244d3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsbase.html @@ -0,0 +1,230 @@ + + + + + + + + nepi.resources.netns.netnsbase — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnsbase

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.execution.attribute import Flags
    +from nepi.execution.trace import TraceAttr
    +
    +@clsinit_copy
    +
    [docs]class NetNSBase(ResourceManager): + _rtype = "abstract::netns::Object" + _platform = "netns" + + def __init__(self, ec, guid): + super(NetNSBase, self).__init__(ec, guid) + self._uuid = None + self._connected = set() + self._trace_filename = dict() + + @property +
    [docs] def connected(self): + return self._connected +
    + @property +
    [docs] def uuid(self): + return self._uuid +
    +
    [docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + filename = self._trace_filename.get(name) + if not filename: + self.error("Can not resolve trace %s. Did you enabled it?" % name) + return "" + + return self.emulation.trace(filename, attr, block, offset) +
    + @property + def _rms_to_wait(self): + """ Returns the collection of RMs that this RM needs to + wait for before start + + This method should be overriden to wait for other + objects to be deployed before proceeding with the deployment + + """ + raise RuntimeError, "No dependencies defined!" + + def _instantiate_object(self): + pass + + def _wait_rms(self): + rms = set() + for rm in self._rms_to_wait: + if rm is not None: + rms.add(rm) + + """ Returns True if dependent RMs are not yer READY, False otherwise""" + for rm in rms: + if rm.state < ResourceState.READY: + return True + return False + +
    [docs] def do_provision(self): + self._instantiate_object() + + self.info("Provisioning finished") + + super(NetNSBase, self).do_provision() +
    +
    [docs] def do_deploy(self): + if self._wait_rms(): + self.debug("---- RESCHEDULING DEPLOY ----" ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def do_start(self): + if self.state == ResourceState.READY: + # No need to do anything, emulation.Run() will start every object + self.info("Starting") + self.set_started() + else: + msg = " Failed " + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def do_stop(self): + if self.state == ResourceState.STARTED: + # No need to do anything, emulation.Destroy() will stop every object + self.set_stopped() +
    + @property +
    [docs] def state(self): + return self._state +
    +
    [docs] def get(self, name): + #flags = Flags.NoWrite | Flags.NoRead | Flags.Design + flags = Flags.Design + if self._state in [ResourceState.READY, ResourceState.STARTED] \ + and not self.has_flag(name, flags): + return self.emulation.emu_get(self.uuid, name) + + value = super(NetNSBase, self).get(name) + return value +
    +
    [docs] def set(self, name, value): + flags = Flags.Design + if (self._state > ResourceState.NEW and \ + self.has_flag(name, Flags.Design)) or \ + self.has_flag(name, Flags.NoWrite): + out = err = "" + msg = " Cannot change Design only attribue %s" % name + self.error(msg, out, err) + return + + if self._state in [ResourceState.READY, ResourceState.STARTED]: + self.emulation.emu_set(self.uuid, name, value) + + value = super(NetNSBase, self).set(name, value) + + return value +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsclient.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsclient.html new file mode 100644 index 00000000..42ff64a3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsclient.html @@ -0,0 +1,132 @@ + + + + + + + + nepi.resources.netns.netnsclient — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnsclient

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +
    [docs]class NetNSClient(object): + """ Common Interface for NS3 client classes """ + def __init__(self): + super(NetNSClient, self).__init__() + +
    [docs] def create(self, *args, **kwargs): + pass +
    +
    [docs] def invoke(self, *args, **kwargs): + pass +
    +
    [docs] def set(self, *args, **kwargs): + pass +
    +
    [docs] def get(self, *args, **kwargs): + pass +
    +
    [docs] def flush(self, *args, **kwargs): + pass +
    +
    [docs] def shutdown(self, *args, **kwargs): + pass +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsemulation.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsemulation.html new file mode 100644 index 00000000..6905f11c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsemulation.html @@ -0,0 +1,132 @@ + + + + + + + + nepi.resources.netns.netnsemulation — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnsemulation

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +
    [docs]class NetNSEmulation(object): + @property +
    [docs] def client(self): + return self._client +
    +
    [docs] def create(self, *args, **kwargs): + return self.client.create(*args, **kwargs) +
    +
    [docs] def invoke(self, *args, **kwargs): + return self.client.invoke(*args, **kwargs) +
    +
    [docs] def emu_set(self, *args, **kwargs): + return self.client.set(*args, **kwargs) +
    +
    [docs] def emu_get(self, *args, **kwargs): + return self.client.get(*args, **kwargs) +
    +
    [docs] def flush(self, *args, **kwargs): + return self.client.flush(*args, **kwargs) +
    +
    [docs] def shutdown(self, *args, **kwargs): + return self.client.shutdown(*args, **kwargs) +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsinterface.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsinterface.html new file mode 100644 index 00000000..5d06bce2 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsinterface.html @@ -0,0 +1,117 @@ + + + + + + + + nepi.resources.netns.netnsinterface — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnsinterface

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.netns.netnsbase import NetNSBase
    +
    +@clsinit_copy
    +
    [docs]class NetNSInterface(NetNSBase): + _rtype = "asbtract::netns::NodeInterface" +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsipv4address.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsipv4address.html new file mode 100644 index 00000000..cf672dff --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsipv4address.html @@ -0,0 +1,153 @@ + + + + + + + + nepi.resources.netns.netnsipv4address — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnsipv4address

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.netns.netnsbase import NetNSBase
    +
    +@clsinit_copy
    +
    [docs]class NetNSIPv4Address(NetNSBase): + _rtype = "netns::IPv4Address" + + @classmethod + def _register_attributes(cls): + ip = Attribute("ip", "IPv4 address", flags=Flags.Design) + prefix = Attribute("prefix", "IPv4 prefix", flags=Flags.Design) + + cls._register_attribute(ip) + cls._register_attribute(prefix) + + @property +
    [docs] def emulation(self): + return self.node.emulation +
    + @property +
    [docs] def node(self): + return self.interface.node +
    + @property +
    [docs] def interface(self): + from nepi.resources.netns.netnsinterface import NetNSInterface + interface = self.get_connected(NetNSInterface.get_rtype()) + + if not interface: + msg = "IPv4Address not connected to Interface!!" + self.error(msg) + raise RuntimeError, msg + + return interface[0] +
    + @property + def _rms_to_wait(self): + return [self.interface] + + def _instantiate_object(self): + self._uuid = self.emulation.invoke(self.interface.uuid, "add_v4_address", + self.get("ip"), self.get("prefix")) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnode.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnode.html new file mode 100644 index 00000000..6fd67736 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnode.html @@ -0,0 +1,137 @@ + + + + + + + + nepi.resources.netns.netnsnode — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnsnode

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.netns.netnsbase import NetNSBase
    +
    +@clsinit_copy
    +
    [docs]class NetNSNode(NetNSBase): + _rtype = "netns::Node" + + @property +
    [docs] def emulation(self): + from nepi.resources.netns.netnsemulation import NetNSEmulation + + for guid in self.connections: + rm = self.ec.get_resource(guid) + if isinstance(rm, NetNSEmulation): + return rm + + msg = "Node not connected to Emulation" + self.error(msg) + raise RuntimeError, msg +
    + @property + def _rms_to_wait(self): + return [self.emulation] + + def _instantiate_object(self): + self._uuid = self.emulation.create("Node") +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnodeinterface.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnodeinterface.html new file mode 100644 index 00000000..dc017fe7 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnodeinterface.html @@ -0,0 +1,157 @@ + + + + + + + + nepi.resources.netns.netnsnodeinterface — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnsnodeinterface

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.netns.netnsinterface import NetNSInterface
    +
    +@clsinit_copy
    +
    [docs]class NetNSNodeInterface(NetNSInterface): + _rtype = "netns::NodeInterface" + + @classmethod + def _register_attributes(cls): + up = Attribute("up", "Interface up", + default = True, + type = Types.Bool) + + cls._register_attribute(up) + + @property +
    [docs] def emulation(self): + return self.node.emulation +
    + @property +
    [docs] def node(self): + from nepi.resources.netns.netnsnode import NetNSNode + node = self.get_connected(NetNSNode.get_rtype()) + + if not node: + msg = "Route not connected to Node!!" + self.error(msg) + raise RuntimeError, msg + + return node[0] +
    + @property +
    [docs] def switch(self): + from nepi.resources.netns.netnsswitch import NetNSSwitch + switch = self.get_connected(NetNSSwitch.get_rtype()) + if switch: return switch[0] + return None +
    + @property + def _rms_to_wait(self): + return [self.node, self.switch] + + def _instantiate_object(self): + self._uuid = self.emulation.invoke(self.node.uuid, "add_if") + self.emulation.invoke(self.switch.uuid, "connect", self.uuid) + self.emulation.emu_set(self.uuid, "up", self.get("up")) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsroute.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsroute.html new file mode 100644 index 00000000..4b4554cc --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsroute.html @@ -0,0 +1,152 @@ + + + + + + + + nepi.resources.netns.netnsroute — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnsroute

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.netns.netnsbase import NetNSBase
    +
    +@clsinit_copy
    +
    [docs]class NetNSIPv4Route(NetNSBase): + _rtype = "netns::IPv4Route" + + @classmethod + def _register_attributes(cls): + network = Attribute("network", "Network address", flags=Flags.Design) + prefix = Attribute("prefix", "IP prefix length", flags=Flags.Design) + nexthop = Attribute("nexthop", "Nexthop IP", flags=Flags.Design) + + cls._register_attribute(network) + cls._register_attribute(prefix) + cls._register_attribute(nexthop) + + @property +
    [docs] def emulation(self): + return self.node.emulation +
    + @property +
    [docs] def node(self): + from nepi.resources.netns.netnsnode import NetNSNode + node = self.get_connected(NetNSNode.get_rtype()) + + if not node: + msg = "Route not connected to Node!!" + self.error(msg) + raise RuntimeError, msg + + return node[0] +
    + @property + def _rms_to_wait(self): + return [self.node] + + def _instantiate_object(self): + self._uuid = self.emulation.invoke(self.device.uuid, "add_route", + prefix=self.get("network"), prefix_len=self.get("prefix"), + nexthop=self.get("nexthop")) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsserver.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsserver.html new file mode 100644 index 00000000..c09bfeb0 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsserver.html @@ -0,0 +1,307 @@ + + + + + + + + nepi.resources.netns.netnsserver — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnsserver

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import base64
    +import cPickle
    +import errno
    +import logging
    +import os
    +import socket
    +import sys
    +
    +from optparse import OptionParser, SUPPRESS_HELP
    +
    +from netnswrapper import NetNSWrapper
    +
    +
    [docs]class NetNSWrapperMessage: + CREATE = "CREATE" + INVOKE = "INVOKE" + SET = "SET" + GET = "GET" + FLUSH = "FLUSH" + SHUTDOWN = "SHUTDOWN" +
    +
    [docs]def handle_message(wrapper, msg_type, args, kwargs): + if msg_type == NetNSWrapperMessage.SHUTDOWN: + wrapper.shutdown() + + return "BYEBYE" + + if msg_type == NetNSWrapperMessage.CREATE: + clazzname = args.pop(0) + + return wrapper.create(clazzname, *args) + + if msg_type == NetNSWrapperMessage.INVOKE: + uuid = args.pop(0) + operation = args.pop(0) + + return wrapper.invoke(uuid, operation, *args, **kwargs) + + if msg_type == NetNSWrapperMessage.GET: + uuid = args.pop(0) + name = args.pop(0) + + return wrapper.get(uuid, name) + + if msg_type == NetNSWrapperMessage.SET: + uuid = args.pop(0) + name = args.pop(0) + value = args.pop(0) + + return wrapper.set(uuid, name, value) + + if msg_type == NetNSWrapperMessage.FLUSH: + # Forces flushing output and error streams. + # NS-3 output will stay unflushed until the program exits or + # explicit invocation flush is done + sys.stdout.flush() + sys.stderr.flush() + + wrapper.logger.debug("FLUSHED") + + return "FLUSHED" +
    +
    [docs]def create_socket(socket_name): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind(socket_name) + return sock +
    +
    [docs]def recv_msg(conn): + msg = [] + chunk = '' + + while '\n' not in chunk: + try: + chunk = conn.recv(1024) + except (OSError, socket.error), e: + if e[0] != errno.EINTR: + raise + # Ignore eintr errors + continue + + if chunk: + msg.append(chunk) + else: + # empty chunk = EOF + break + + msg = ''.join(msg).strip() + + # The message is formatted as follows: + # MESSAGE_TYPE|args|kwargs + # + # where MESSAGE_TYPE, args and kwargs are pickld and enoded in base64 + + def decode(item): + item = base64.b64decode(item).rstrip() + return cPickle.loads(item) + + decoded = map(decode, msg.split("|")) + + # decoded message + dmsg_type = decoded.pop(0) + dargs = list(decoded.pop(0)) # transforming touple into list + dkwargs = decoded.pop(0) + + return (dmsg_type, dargs, dkwargs) +
    +
    [docs]def send_reply(conn, reply): + encoded = base64.b64encode(cPickle.dumps(reply)) + conn.send("%s\n" % encoded) +
    +
    [docs]def get_options(): + usage = ("usage: %prog -S <socket-name> -D <enable-dump> -v ") + + parser = OptionParser(usage = usage) + + parser.add_option("-S", "--socket-name", dest="socket_name", + help = "Name for the unix socket used to interact with this process", + default = "tap.sock", type="str") + + parser.add_option("-D", "--enable-dump", dest="enable_dump", + help = "Enable dumping the remote executed commands to a script " + "in order to later reproduce and debug the experiment", + action = "store_true", + default = False) + + parser.add_option("-v", "--verbose", + help="Print debug output", + action="store_true", + dest="verbose", default=False) + + (options, args) = parser.parse_args() + + return (options.socket_name, options.verbose, options.enable_dump) +
    +
    [docs]def run_server(socket_name, level = logging.INFO, + enable_dump = False): + + ###### wrapper instantiation + if level == logging.DEBUG: + from syslog import LOG_DEBUG + import netns + netns.environ.set_log_level(LOG_DEBUG) + + wrapper = NetNSWrapper(loglevel=level, enable_dump = enable_dump) + + wrapper.logger.info("STARTING...") + + # create unix socket to receive instructions + sock = create_socket(socket_name) + sock.listen(0) + + # wait for messages to arrive and process them + stop = False + + while not stop: + conn, addr = sock.accept() + conn.settimeout(5) + + try: + (msg_type, args, kwargs) = recv_msg(conn) + except socket.timeout, e: + # Ingore time-out + continue + + if not msg_type: + # Ignore - connection lost + break + + if msg_type == NetNSWrapperMessage.SHUTDOWN: + stop = True + + try: + reply = handle_message(wrapper, msg_type, args, kwargs) + except: + import traceback + err = traceback.format_exc() + wrapper.logger.error(err) + raise + + try: + send_reply(conn, reply) + except socket.error: + break + + wrapper.logger.info("EXITING...") +
    +if __name__ == '__main__': + + (socket_name, verbose, enable_dump) = get_options() + + ## configure logging + FORMAT = "%(asctime)s %(name)s %(levelname)-4s %(message)s" + level = logging.DEBUG if verbose else logging.INFO + + logging.basicConfig(format = FORMAT, level = level) + + ## Run the server + run_server(socket_name, level, enable_dump) +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsswitch.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsswitch.html new file mode 100644 index 00000000..eabd651c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsswitch.html @@ -0,0 +1,153 @@ + + + + + + + + nepi.resources.netns.netnsswitch — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnsswitch

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.netns.netnsbase import NetNSBase
    +
    +@clsinit_copy
    +
    [docs]class NetNSSwitch(NetNSBase): + _rtype = "netns::Switch" + + @classmethod + def _register_attributes(cls): + up = Attribute("up", "Switch up", + default = True, + type = Types.Bool) + + cls._register_attribute(up) + + @property +
    [docs] def emulation(self): + return self.node.emulation +
    + @property +
    [docs] def node(self): + return self.interface.node +
    + @property +
    [docs] def interface(self): + from nepi.resources.netns.netnsinterface import NetNSInterface + interface = self.get_connected(NetNSInterface.get_rtype()) + + if not interface: + msg = "Switch not connected to any Interface!!" + self.error(msg) + raise RuntimeError, msg + + return interface[0] +
    + @property + def _rms_to_wait(self): + return [self.emulation] + + def _instantiate_object(self): + self._uuid = self.emulation.create("Switch") + self.emulation.emu_set(self.uuid, "up", self.get("up")) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper.html new file mode 100644 index 00000000..74dc3173 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper.html @@ -0,0 +1,280 @@ + + + + + + + + nepi.resources.netns.netnswrapper — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnswrapper

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import logging
    +import time
    +import os
    +import sys
    +import uuid
    +
    +
    [docs]class NetNSWrapper(object): + def __init__(self, loglevel = logging.INFO, enable_dump = False): + super(NetNSWrapper, self).__init__() + # holds reference to all C++ objects and variables in the simulation + self._objects = dict() + + # Logging + self._logger = logging.getLogger("netnswrapper") + self._logger.setLevel(loglevel) + + # Object to dump instructions to reproduce and debug experiment + from netnswrapper_debug import NetNSWrapperDebuger + self._debuger = NetNSWrapperDebuger(enabled = enable_dump) + + @property +
    [docs] def debuger(self): + return self._debuger +
    + @property +
    [docs] def logger(self): + return self._logger +
    +
    [docs] def make_uuid(self): + return "uuid%s" % uuid.uuid4() +
    +
    [docs] def get_object(self, uuid): + return self._objects.get(uuid) +
    +
    [docs] def create(self, clazzname, *args): + """ This method should be used to construct netns objects """ + import netns + + if clazzname not in ['open'] and not hasattr(netns, clazzname): + msg = "Type %s not supported" % (clazzname) + self.logger.error(msg) + + uuid = self.make_uuid() + + ### DEBUG + self.logger.debug("CREATE %s( %s )" % (clazzname, str(args))) + + self.debuger.dump_create(uuid, clazzname, args) + ######## + + if clazzname == "open": + path = args[0] + mode = args[1] + obj = open(path, mode) + else: + clazz = getattr(netns, clazzname) + + # arguments starting with 'uuid' identify ns-3 C++ + # objects and must be replaced by the actual object + realargs = self.replace_args(args) + + obj = clazz(*realargs) + + self._objects[uuid] = obj + + ### DEBUG + self.logger.debug("RET CREATE ( uuid %s ) %s = %s( %s )" % (str(uuid), + str(obj), clazzname, str(args))) + ######## + + return uuid +
    +
    [docs] def invoke(self, uuid, operation, *args, **kwargs): + newuuid = self.make_uuid() + + ### DEBUG + self.logger.debug("INVOKE %s -> %s( %s, %s ) " % ( + uuid, operation, str(args), str(kwargs))) + + self.debuger.dump_invoke(newuuid, uuid, operation, args, kwargs) + ######## + + obj = self.get_object(uuid) + + method = getattr(obj, operation) + + # arguments starting with 'uuid' identify netns + # objects and must be replaced by the actual object + realargs = self.replace_args(args) + realkwargs = self.replace_kwargs(kwargs) + + result = method(*realargs, **realkwargs) + + # If the result is an object (not a base value), + # then keep track of the object a return the object + # reference (newuuid) + if not (result is None or type(result) in [ + bool, float, long, str, int]): + self._objects[newuuid] = result + result = newuuid + + ### DEBUG + self.logger.debug("RET INVOKE %s%s = %s -> %s(%s, %s) " % ( + "(uuid %s) " % str(newuuid) if newuuid else "", str(result), uuid, + operation, str(args), str(kwargs))) + ######## + + return result +
    +
    [docs] def set(self, uuid, name, value): + ### DEBUG + self.logger.debug("SET %s %s %s" % (uuid, name, str(value))) + + self.debuger.dump_set(uuid, name, value) + ######## + + obj = self.get_object(uuid) + setattr(obj, name, value) + + ### DEBUG + self.logger.debug("RET SET %s = %s -> set(%s, %s)" % (str(value), uuid, name, + str(value))) + ######## + + return value +
    +
    [docs] def get(self, uuid, name): + ### DEBUG + self.logger.debug("GET %s %s" % (uuid, name)) + + self.debuger.dump_get(uuid, name) + ######## + + obj = self.get_object(uuid) + result = getattr(obj, name) + + ### DEBUG + self.logger.debug("RET GET %s = %s -> get(%s)" % (str(result), uuid, name)) + ######## + + return result +
    +
    [docs] def shutdown(self): + ### DEBUG + self.debuger.dump_shutdown() + ######## + + ### FLUSH PIPES + sys.stdout.flush() + sys.stderr.flush() + + ### RELEASE OBJECTS + del self._objects + + ### DEBUG + self.logger.debug("SHUTDOWN") + ######## +
    +
    [docs] def replace_args(self, args): + realargs = [self.get_object(arg) if \ + str(arg).startswith("uuid") else arg for arg in args] + + return realargs +
    +
    [docs] def replace_kwargs(self, kwargs): + realkwargs = dict([(k, self.get_object(v) \ + if str(v).startswith("uuid") else v) \ + for k,v in kwargs.iteritems()]) + + return realkwargs +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper_debug.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper_debug.html new file mode 100644 index 00000000..e6af9c76 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper_debug.html @@ -0,0 +1,251 @@ + + + + + + + + nepi.resources.netns.netnswrapper_debug — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.netns.netnswrapper_debug

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +
    +############ METHODS DEBUG NETNSWRAPPER EXECUTION
    +##
    +## The netnswrapper works in ditributed mode, receiving instructions from
    +## a remote client. This makes it very hard to debug scripting errors 
    +## in the client side. To simplify error debugging, when set to debug mode,
    +## the ns3wrapper dumps every executed line to a script that can be then
    +## executed locally to reproduce and debug the experiment.
    +##
    +###########################################################################
    +
    +import logging
    +
    +
    [docs]class NetNSWrapperDebuger(object): + def __init__(self, enabled): + super(NetNSWrapperDebuger, self).__init__() + self._enabled = enabled + self._script_path = "debug.py" + + self.dump_header() + + @property +
    [docs] def enabled(self): + return self._enabled +
    + @property +
    [docs] def script_path(self): + return self._script_path +
    +
    [docs] def dump_to_script(self, command): + f = open(self.script_path, "a") + f.write("%s" % command) + f.close() +
    +
    [docs] def dump_header(self): + if not self.enabled: + return + + header = """ +from netnswrapper import NetNSWrapper + +wrapper = NS3Wrapper() + +""" + self.dump_to_script(header) +
    +
    [docs] def dump_factory(self, uuid, type_name, kwargs): + if not self.enabled: + return + + command = ("kwargs = %(kwargs)s\n" + "%(uuid)s = wrapper.factory(%(type_name)s, **kwargs)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "type_name": self.format_value(type_name), + "kwargs": self.format_kwargs(kwargs) + }) + + self.dump_to_script(command) +
    +
    [docs] def dump_create(self, uuid, clazzname, args): + if not self.enabled: + return + + command = ("args = %(args)s\n" + "%(uuid)s = wrapper.create(%(clazzname)s, *args)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "clazzname": self.format_value(clazzname), + "args": self.format_args(args), + }) + + self.dump_to_script(command) +
    +
    [docs] def dump_invoke(self, newuuid, uuid, operation, args, kwargs): + if not self.enabled: + return + + command = ("args = %(args)s\n" + "kwargs = %(kwargs)s\n" + "%(newuuid)s = wrapper.invoke(%(uuid)s, %(operation)s, *args, **kwargs)\n\n" + ) % dict({ + "newuuid": self.format_value(newuuid) if newuuid else "nothing", + "uuid": self.format_value(uuid), + "operation": self.format_value(operation), + "args": self.format_args(args), + "kwargs": self.format_kwargs(kwargs), + }) + + self.dump_to_script(command) +
    +
    [docs] def dump_set(self, uuid, name, value): + if not self.enabled: + return + + command = ("wrapper.set(%(uuid)s, %(name)s, %(value)s)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "name": self.format_value(name), + "value": self.format_value(value), + }) + + self.dump_to_script(command) +
    +
    [docs] def dump_get(self, uuid, name): + if not self.enabled: + return + + command = ("wrapper.get(%(uuid)s, %(name)s)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "name": self.format_value(name), + }) + + self.dump_to_script(command) +
    +
    [docs] def dump_shutdown(self): + if not self.enabled: + return + + command = "wrapper.shutdown()\n\n" + self.dump_to_script(command) +
    +
    [docs] def format_value(self, value): + if isinstance(value, str) and value.startswith("uuid"): + return value.replace("-", "") + + import pprint + return pprint.pformat(value) +
    +
    [docs] def format_args(self, args): + fargs = map(self.format_value, args) + return "[%s]" % ",".join(fargs) +
    +
    [docs] def format_kwargs(self, kwargs): + fkwargs = map(lambda (k,w): + "%s: %s" % (self.format_value(k), self.format_value(w)), + kwargs.iteritems()) + + return "dict({%s})" % ",".join(fkwargs) +
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarf_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarf_wifi_manager.html new file mode 100644 index 00000000..74f31e76 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarf_wifi_manager.html @@ -0,0 +1,268 @@ + + + + + + + + nepi.resources.ns3.classes.aarf_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.aarf_wifi_manager

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
    +
    +@clsinit_copy
    +
    [docs]class NS3AarfWifiManager(NS3BaseWifiRemoteStationManager): + _rtype = "ns3::AarfWifiManager" + + @classmethod + def _register_attributes(cls): + + attr_successk = Attribute("SuccessK", + "Multiplication factor for the success threshold in the AARF algorithm.", + type = Types.Double, + default = "2", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_successk) + + attr_timerk = Attribute("TimerK", + "Multiplication factor for the timer threshold in the AARF algorithm.", + type = Types.Double, + default = "2", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_timerk) + + attr_maxsuccessthreshold = Attribute("MaxSuccessThreshold", + "Maximum value of the success threshold in the AARF algorithm.", + type = Types.Integer, + default = "60", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxsuccessthreshold) + + attr_mintimerthreshold = Attribute("MinTimerThreshold", + "The minimum value for the \'timer\' threshold in the AARF algorithm.", + type = Types.Integer, + default = "15", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mintimerthreshold) + + attr_minsuccessthreshold = Attribute("MinSuccessThreshold", + "The minimum value for the success threshold in the AARF algorithm.", + type = Types.Integer, + default = "10", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_minsuccessthreshold) + + attr_islowlatency = Attribute("IsLowLatency", + "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_islowlatency) + + attr_maxssrc = Attribute("MaxSsrc", + "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxssrc) + + attr_maxslrc = Attribute("MaxSlrc", + "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxslrc) + + attr_rtsctsthreshold = Attribute("RtsCtsThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2012, Section 9.3.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rtsctsthreshold) + + attr_fragmentationthreshold = Attribute("FragmentationThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2012, Section 9.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentationthreshold) + + attr_nonunicastmode = Attribute("NonUnicastMode", + "Wifi mode used for non-unicast transmissions.", + type = Types.String, + default = "Invalid-WifiMode", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_nonunicastmode) + + attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel", + "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaulttxpowerlevel) + + + + @classmethod + def _register_traces(cls): + + mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed") + + cls._register_trace(mactxrtsfailed) + + mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed") + + cls._register_trace(mactxdatafailed) + + mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinalrtsfailed) + + mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinaldatafailed) + + + + def __init__(self, ec, guid): + super(NS3AarfWifiManager, self).__init__(ec, guid) + self._home = "ns3-aarf-wifi-manager-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarfcd_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarfcd_wifi_manager.html new file mode 100644 index 00000000..171bd476 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarfcd_wifi_manager.html @@ -0,0 +1,308 @@ + + + + + + + + nepi.resources.ns3.classes.aarfcd_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.aarfcd_wifi_manager

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
    +
    +@clsinit_copy
    +
    [docs]class NS3AarfcdWifiManager(NS3BaseWifiRemoteStationManager): + _rtype = "ns3::AarfcdWifiManager" + + @classmethod + def _register_attributes(cls): + + attr_successk = Attribute("SuccessK", + "Multiplication factor for the success threshold in the AARF algorithm.", + type = Types.Double, + default = "2", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_successk) + + attr_timerk = Attribute("TimerK", + "Multiplication factor for the timer threshold in the AARF algorithm.", + type = Types.Double, + default = "2", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_timerk) + + attr_maxsuccessthreshold = Attribute("MaxSuccessThreshold", + "Maximum value of the success threshold in the AARF algorithm.", + type = Types.Integer, + default = "60", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxsuccessthreshold) + + attr_mintimerthreshold = Attribute("MinTimerThreshold", + "The minimum value for the \'timer\' threshold in the AARF algorithm.", + type = Types.Integer, + default = "15", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mintimerthreshold) + + attr_minsuccessthreshold = Attribute("MinSuccessThreshold", + "The minimum value for the success threshold in the AARF algorithm.", + type = Types.Integer, + default = "10", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_minsuccessthreshold) + + attr_minrtswnd = Attribute("MinRtsWnd", + "Minimum value for Rts window of Aarf-CD", + type = Types.Integer, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_minrtswnd) + + attr_maxrtswnd = Attribute("MaxRtsWnd", + "Maximum value for Rts window of Aarf-CD", + type = Types.Integer, + default = "40", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxrtswnd) + + attr_turnoffrtsafterratedecrease = Attribute("TurnOffRtsAfterRateDecrease", + "If true the RTS mechanism will be turned off when the rate will be decreased", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_turnoffrtsafterratedecrease) + + attr_turnonrtsafterrateincrease = Attribute("TurnOnRtsAfterRateIncrease", + "If true the RTS mechanism will be turned on when the rate will be increased", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_turnonrtsafterrateincrease) + + attr_islowlatency = Attribute("IsLowLatency", + "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_islowlatency) + + attr_maxssrc = Attribute("MaxSsrc", + "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxssrc) + + attr_maxslrc = Attribute("MaxSlrc", + "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxslrc) + + attr_rtsctsthreshold = Attribute("RtsCtsThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2012, Section 9.3.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rtsctsthreshold) + + attr_fragmentationthreshold = Attribute("FragmentationThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2012, Section 9.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentationthreshold) + + attr_nonunicastmode = Attribute("NonUnicastMode", + "Wifi mode used for non-unicast transmissions.", + type = Types.String, + default = "Invalid-WifiMode", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_nonunicastmode) + + attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel", + "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaulttxpowerlevel) + + + + @classmethod + def _register_traces(cls): + + mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed") + + cls._register_trace(mactxrtsfailed) + + mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed") + + cls._register_trace(mactxdatafailed) + + mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinalrtsfailed) + + mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinaldatafailed) + + + + def __init__(self, ec, guid): + super(NS3AarfcdWifiManager, self).__init__(ec, guid) + self._home = "ns3-aarfcd-wifi-manager-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/adhoc_wifi_mac.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/adhoc_wifi_mac.html new file mode 100644 index 00000000..87e71c70 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/adhoc_wifi_mac.html @@ -0,0 +1,300 @@ + + + + + + + + nepi.resources.ns3.classes.adhoc_wifi_mac — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.adhoc_wifi_mac

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
    +
    +@clsinit_copy
    +
    [docs]class NS3AdhocWifiMac(NS3BaseWifiMac): + _rtype = "ns3::AdhocWifiMac" + + @classmethod + def _register_attributes(cls): + + attr_qossupported = Attribute("QosSupported", + "This Boolean attribute is set to enable 802.11e/WMM-style QoS support at this STA", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_qossupported) + + attr_htsupported = Attribute("HtSupported", + "This Boolean attribute is set to enable 802.11n support at this STA", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_htsupported) + + attr_ctstoselfsupported = Attribute("CtsToSelfSupported", + "Use CTS to Self when using a rate that is not in the basic set rate", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ctstoselfsupported) + + attr_ctstimeout = Attribute("CtsTimeout", + "When this timeout expires, the RTS/CTS handshake has failed.", + type = Types.String, + default = "+75000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ctstimeout) + + attr_acktimeout = Attribute("AckTimeout", + "When this timeout expires, the DATA/ACK handshake has failed.", + type = Types.String, + default = "+75000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_acktimeout) + + attr_basicblockacktimeout = Attribute("BasicBlockAckTimeout", + "When this timeout expires, the BASIC_BLOCK_ACK_REQ/BASIC_BLOCK_ACK handshake has failed.", + type = Types.String, + default = "+281000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_basicblockacktimeout) + + attr_compressedblockacktimeout = Attribute("CompressedBlockAckTimeout", + "When this timeout expires, the COMPRESSED_BLOCK_ACK_REQ/COMPRESSED_BLOCK_ACK handshake has failed.", + type = Types.String, + default = "+107000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_compressedblockacktimeout) + + attr_sifs = Attribute("Sifs", + "The value of the SIFS constant.", + type = Types.String, + default = "+16000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_sifs) + + attr_eifsnodifs = Attribute("EifsNoDifs", + "The value of EIFS-DIFS", + type = Types.String, + default = "+60000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_eifsnodifs) + + attr_slot = Attribute("Slot", + "The duration of a Slot.", + type = Types.String, + default = "+9000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_slot) + + attr_pifs = Attribute("Pifs", + "The value of the PIFS constant.", + type = Types.String, + default = "+25000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pifs) + + attr_rifs = Attribute("Rifs", + "The value of the RIFS constant.", + type = Types.String, + default = "+2000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rifs) + + attr_maxpropagationdelay = Attribute("MaxPropagationDelay", + "The maximum propagation delay. Unused for now.", + type = Types.String, + default = "+3333.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxpropagationdelay) + + attr_ssid = Attribute("Ssid", + "The ssid we want to belong to.", + type = Types.String, + default = "default", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ssid) + + + + @classmethod + def _register_traces(cls): + + txokheader = Trace("TxOkHeader", "The header of successfully transmitted packet") + + cls._register_trace(txokheader) + + txerrheader = Trace("TxErrHeader", "The header of unsuccessfully transmitted packet") + + cls._register_trace(txerrheader) + + mactx = Trace("MacTx", "A packet has been received from higher layers and is being processed in preparation for queueing for transmission.") + + cls._register_trace(mactx) + + mactxdrop = Trace("MacTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.") + + cls._register_trace(mactxdrop) + + macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(macpromiscrx) + + macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(macrx) + + macrxdrop = Trace("MacRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.") + + cls._register_trace(macrxdrop) + + + + def __init__(self, ec, guid): + super(NS3AdhocWifiMac, self).__init__(ec, guid) + self._home = "ns3-adhoc-wifi-mac-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aloha_noack_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aloha_noack_net_device.html new file mode 100644 index 00000000..92e63c07 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aloha_noack_net_device.html @@ -0,0 +1,168 @@ + + + + + + + + nepi.resources.ns3.classes.aloha_noack_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.aloha_noack_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3AlohaNoackNetDevice(NS3BaseNetDevice): + _rtype = "ns3::AlohaNoackNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_address = Attribute("Address", + "The MAC address of this device.", + type = Types.String, + default = "12:34:56:78:90:12", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_address) + + attr_mtu = Attribute("Mtu", + "The Maximum Transmission Unit", + type = Types.Integer, + default = "1500", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + + + @classmethod + def _register_traces(cls): + + mactx = Trace("MacTx", "Trace source indicating a packet has arrived for transmission by this device") + + cls._register_trace(mactx) + + mactxdrop = Trace("MacTxDrop", "Trace source indicating a packet has been dropped by the device before transmission") + + cls._register_trace(mactxdrop) + + macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(macpromiscrx) + + macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(macrx) + + + + def __init__(self, ec, guid): + super(NS3AlohaNoackNetDevice, self).__init__(ec, guid) + self._home = "ns3-aloha-noack-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/amrr_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/amrr_wifi_manager.html new file mode 100644 index 00000000..24d667cd --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/amrr_wifi_manager.html @@ -0,0 +1,268 @@ + + + + + + + + nepi.resources.ns3.classes.amrr_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.amrr_wifi_manager

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
    +
    +@clsinit_copy
    +
    [docs]class NS3AmrrWifiManager(NS3BaseWifiRemoteStationManager): + _rtype = "ns3::AmrrWifiManager" + + @classmethod + def _register_attributes(cls): + + attr_updateperiod = Attribute("UpdatePeriod", + "The interval between decisions about rate control changes", + type = Types.String, + default = "+1000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_updateperiod) + + attr_failureratio = Attribute("FailureRatio", + "Ratio of minimum erroneous transmissions needed to switch to a lower rate", + type = Types.Double, + default = "0.333333", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_failureratio) + + attr_successratio = Attribute("SuccessRatio", + "Ratio of maximum erroneous transmissions needed to switch to a higher rate", + type = Types.Double, + default = "0.1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_successratio) + + attr_maxsuccessthreshold = Attribute("MaxSuccessThreshold", + "Maximum number of consecutive success periods needed to switch to a higher rate", + type = Types.Integer, + default = "10", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxsuccessthreshold) + + attr_minsuccessthreshold = Attribute("MinSuccessThreshold", + "Minimum number of consecutive success periods needed to switch to a higher rate", + type = Types.Integer, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_minsuccessthreshold) + + attr_islowlatency = Attribute("IsLowLatency", + "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_islowlatency) + + attr_maxssrc = Attribute("MaxSsrc", + "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxssrc) + + attr_maxslrc = Attribute("MaxSlrc", + "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxslrc) + + attr_rtsctsthreshold = Attribute("RtsCtsThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2012, Section 9.3.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rtsctsthreshold) + + attr_fragmentationthreshold = Attribute("FragmentationThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2012, Section 9.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentationthreshold) + + attr_nonunicastmode = Attribute("NonUnicastMode", + "Wifi mode used for non-unicast transmissions.", + type = Types.String, + default = "Invalid-WifiMode", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_nonunicastmode) + + attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel", + "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaulttxpowerlevel) + + + + @classmethod + def _register_traces(cls): + + mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed") + + cls._register_trace(mactxrtsfailed) + + mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed") + + cls._register_trace(mactxdatafailed) + + mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinalrtsfailed) + + mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinaldatafailed) + + + + def __init__(self, ec, guid): + super(NS3AmrrWifiManager, self).__init__(ec, guid) + self._home = "ns3-amrr-wifi-manager-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ap_wifi_mac.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ap_wifi_mac.html new file mode 100644 index 00000000..745cddc4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ap_wifi_mac.html @@ -0,0 +1,340 @@ + + + + + + + + nepi.resources.ns3.classes.ap_wifi_mac — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.ap_wifi_mac

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
    +
    +@clsinit_copy
    +
    [docs]class NS3ApWifiMac(NS3BaseWifiMac): + _rtype = "ns3::ApWifiMac" + + @classmethod + def _register_attributes(cls): + + attr_beaconinterval = Attribute("BeaconInterval", + "Delay between two beacons", + type = Types.String, + default = "+102400000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_beaconinterval) + + attr_beaconjitter = Attribute("BeaconJitter", + "A uniform random variable to cause the initial beacon starting time (after simulation time 0) to be distributed between 0 and the BeaconInterval.", + type = Types.String, + default = "ns3::UniformRandomVariable", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_beaconjitter) + + attr_enablebeaconjitter = Attribute("EnableBeaconJitter", + "If beacons are enabled, whether to jitter the initial send event.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_enablebeaconjitter) + + attr_beacongeneration = Attribute("BeaconGeneration", + "Whether or not beacons are generated.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_beacongeneration) + + attr_qossupported = Attribute("QosSupported", + "This Boolean attribute is set to enable 802.11e/WMM-style QoS support at this STA", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_qossupported) + + attr_htsupported = Attribute("HtSupported", + "This Boolean attribute is set to enable 802.11n support at this STA", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_htsupported) + + attr_ctstoselfsupported = Attribute("CtsToSelfSupported", + "Use CTS to Self when using a rate that is not in the basic set rate", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ctstoselfsupported) + + attr_ctstimeout = Attribute("CtsTimeout", + "When this timeout expires, the RTS/CTS handshake has failed.", + type = Types.String, + default = "+75000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ctstimeout) + + attr_acktimeout = Attribute("AckTimeout", + "When this timeout expires, the DATA/ACK handshake has failed.", + type = Types.String, + default = "+75000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_acktimeout) + + attr_basicblockacktimeout = Attribute("BasicBlockAckTimeout", + "When this timeout expires, the BASIC_BLOCK_ACK_REQ/BASIC_BLOCK_ACK handshake has failed.", + type = Types.String, + default = "+281000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_basicblockacktimeout) + + attr_compressedblockacktimeout = Attribute("CompressedBlockAckTimeout", + "When this timeout expires, the COMPRESSED_BLOCK_ACK_REQ/COMPRESSED_BLOCK_ACK handshake has failed.", + type = Types.String, + default = "+107000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_compressedblockacktimeout) + + attr_sifs = Attribute("Sifs", + "The value of the SIFS constant.", + type = Types.String, + default = "+16000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_sifs) + + attr_eifsnodifs = Attribute("EifsNoDifs", + "The value of EIFS-DIFS", + type = Types.String, + default = "+60000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_eifsnodifs) + + attr_slot = Attribute("Slot", + "The duration of a Slot.", + type = Types.String, + default = "+9000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_slot) + + attr_pifs = Attribute("Pifs", + "The value of the PIFS constant.", + type = Types.String, + default = "+25000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pifs) + + attr_rifs = Attribute("Rifs", + "The value of the RIFS constant.", + type = Types.String, + default = "+2000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rifs) + + attr_maxpropagationdelay = Attribute("MaxPropagationDelay", + "The maximum propagation delay. Unused for now.", + type = Types.String, + default = "+3333.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxpropagationdelay) + + attr_ssid = Attribute("Ssid", + "The ssid we want to belong to.", + type = Types.String, + default = "default", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ssid) + + + + @classmethod + def _register_traces(cls): + + txokheader = Trace("TxOkHeader", "The header of successfully transmitted packet") + + cls._register_trace(txokheader) + + txerrheader = Trace("TxErrHeader", "The header of unsuccessfully transmitted packet") + + cls._register_trace(txerrheader) + + mactx = Trace("MacTx", "A packet has been received from higher layers and is being processed in preparation for queueing for transmission.") + + cls._register_trace(mactx) + + mactxdrop = Trace("MacTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.") + + cls._register_trace(mactxdrop) + + macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(macpromiscrx) + + macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(macrx) + + macrxdrop = Trace("MacRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.") + + cls._register_trace(macrxdrop) + + + + def __init__(self, ec, guid): + super(NS3ApWifiMac, self).__init__(ec, guid) + self._home = "ns3-ap-wifi-mac-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arf_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arf_wifi_manager.html new file mode 100644 index 00000000..7985d569 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arf_wifi_manager.html @@ -0,0 +1,238 @@ + + + + + + + + nepi.resources.ns3.classes.arf_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.arf_wifi_manager

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
    +
    +@clsinit_copy
    +
    [docs]class NS3ArfWifiManager(NS3BaseWifiRemoteStationManager): + _rtype = "ns3::ArfWifiManager" + + @classmethod + def _register_attributes(cls): + + attr_timerthreshold = Attribute("TimerThreshold", + "The \'timer\' threshold in the ARF algorithm.", + type = Types.Integer, + default = "15", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_timerthreshold) + + attr_successthreshold = Attribute("SuccessThreshold", + "The minimum number of sucessfull transmissions to try a new rate.", + type = Types.Integer, + default = "10", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_successthreshold) + + attr_islowlatency = Attribute("IsLowLatency", + "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_islowlatency) + + attr_maxssrc = Attribute("MaxSsrc", + "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxssrc) + + attr_maxslrc = Attribute("MaxSlrc", + "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxslrc) + + attr_rtsctsthreshold = Attribute("RtsCtsThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2012, Section 9.3.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rtsctsthreshold) + + attr_fragmentationthreshold = Attribute("FragmentationThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2012, Section 9.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentationthreshold) + + attr_nonunicastmode = Attribute("NonUnicastMode", + "Wifi mode used for non-unicast transmissions.", + type = Types.String, + default = "Invalid-WifiMode", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_nonunicastmode) + + attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel", + "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaulttxpowerlevel) + + + + @classmethod + def _register_traces(cls): + + mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed") + + cls._register_trace(mactxrtsfailed) + + mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed") + + cls._register_trace(mactxdatafailed) + + mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinalrtsfailed) + + mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinaldatafailed) + + + + def __init__(self, ec, guid): + super(NS3ArfWifiManager, self).__init__(ec, guid) + self._home = "ns3-arf-wifi-manager-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arp_l3protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arp_l3protocol.html new file mode 100644 index 00000000..7eb70fe4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arp_l3protocol.html @@ -0,0 +1,146 @@ + + + + + + + + nepi.resources.ns3.classes.arp_l3protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.arp_l3protocol

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3arpl3protocol import NS3BaseArpL3Protocol 
    +
    +@clsinit_copy
    +
    [docs]class NS3ArpL3Protocol(NS3BaseArpL3Protocol): + _rtype = "ns3::ArpL3Protocol" + + @classmethod + def _register_attributes(cls): + + attr_requestjitter = Attribute("RequestJitter", + "The jitter in ms a node is allowed to wait before sending an ARP request. Some jitter aims to prevent collisions. By default, the model will wait for a duration in ms defined by a uniform random-variable between 0 and RequestJitter", + type = Types.String, + default = "ns3::UniformRandomVariable[Min=0.0|Max=10.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_requestjitter) + + + + @classmethod + def _register_traces(cls): + + drop = Trace("Drop", "Packet dropped because not enough room in pending queue for a specific cache entry.") + + cls._register_trace(drop) + + + + def __init__(self, ec, guid): + super(NS3ArpL3Protocol, self).__init__(ec, guid) + self._home = "ns3-arp-l3protocol-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/base_station_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/base_station_net_device.html new file mode 100644 index 00000000..72e712ce --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/base_station_net_device.html @@ -0,0 +1,260 @@ + + + + + + + + nepi.resources.ns3.classes.base_station_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.base_station_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseStationNetDevice(NS3BaseNetDevice): + _rtype = "ns3::BaseStationNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_initialranginterval = Attribute("InitialRangInterval", + "Time between Initial Ranging regions assigned by the BS. Maximum is 2s", + type = Types.String, + default = "+50000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_initialranginterval) + + attr_dcdinterval = Attribute("DcdInterval", + "Time between transmission of DCD messages. Maximum value is 10s.", + type = Types.String, + default = "+3000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_dcdinterval) + + attr_ucdinterval = Attribute("UcdInterval", + "Time between transmission of UCD messages. Maximum value is 10s.", + type = Types.String, + default = "+3000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ucdinterval) + + attr_intervalt8 = Attribute("IntervalT8", + "Wait for DSA/DSC Acknowledge timeout. Maximum 300ms.", + type = Types.String, + default = "+50000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_intervalt8) + + attr_rangreqoppsize = Attribute("RangReqOppSize", + "The ranging opportunity size in symbols", + type = Types.Integer, + default = "8", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rangreqoppsize) + + attr_bwreqoppsize = Attribute("BwReqOppSize", + "The bandwidth request opportunity size in symbols", + type = Types.Integer, + default = "2", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_bwreqoppsize) + + attr_maxrangcorrectionretries = Attribute("MaxRangCorrectionRetries", + "Number of retries on contention Ranging Requests", + type = Types.Integer, + default = "16", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxrangcorrectionretries) + + attr_mtu = Attribute("Mtu", + "The MAC-level Maximum Transmission Unit", + type = Types.Integer, + default = "1400", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + attr_rtg = Attribute("RTG", + "receive/transmit transition gap.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rtg) + + attr_ttg = Attribute("TTG", + "transmit/receive transition gap.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ttg) + + + + @classmethod + def _register_traces(cls): + + bstx = Trace("BSTx", "A packet has been received from higher layers and is being processed in preparation for queueing for transmission.") + + cls._register_trace(bstx) + + bstxdrop = Trace("BSTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.") + + cls._register_trace(bstxdrop) + + bspromiscrx = Trace("BSPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(bspromiscrx) + + bsrx = Trace("BSRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(bsrx) + + bsrxdrop = Trace("BSRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.") + + cls._register_trace(bsrxdrop) + + rx = Trace("Rx", "Receive trace") + + cls._register_trace(rx) + + tx = Trace("Tx", "Transmit trace") + + cls._register_trace(tx) + + + + def __init__(self, ec, guid): + super(NS3BaseStationNetDevice, self).__init__(ec, guid) + self._home = "ns3-base-station-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_model.html new file mode 100644 index 00000000..3c6de282 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.binary_error_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.binary_error_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3BinaryErrorModel(NS3BaseErrorModel): + _rtype = "ns3::BinaryErrorModel" + + @classmethod + def _register_attributes(cls): + + attr_isenabled = Attribute("IsEnabled", + "Whether this ErrorModel is enabled or not.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_isenabled) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3BinaryErrorModel, self).__init__(ec, guid) + self._home = "ns3-binary-error-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_sixlow_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_sixlow_model.html new file mode 100644 index 00000000..c31a7e7d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_sixlow_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.binary_error_sixlow_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.binary_error_sixlow_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3BinaryErrorSixlowModel(NS3BaseErrorModel): + _rtype = "ns3::BinaryErrorSixlowModel" + + @classmethod + def _register_attributes(cls): + + attr_isenabled = Attribute("IsEnabled", + "Whether this ErrorModel is enabled or not.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_isenabled) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3BinaryErrorSixlowModel, self).__init__(ec, guid) + self._home = "ns3-binary-error-sixlow-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_channel.html new file mode 100644 index 00000000..0477b2f7 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_channel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.bridge_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.bridge_channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3channel import NS3BaseChannel 
    +
    +@clsinit_copy
    +
    [docs]class NS3BridgeChannel(NS3BaseChannel): + _rtype = "ns3::BridgeChannel" + + @classmethod + def _register_attributes(cls): + + attr_id = Attribute("Id", + "The id (unique integer) of this Channel.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_id) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3BridgeChannel, self).__init__(ec, guid) + self._home = "ns3-bridge-channel-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_net_device.html new file mode 100644 index 00000000..ad5f76f9 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_net_device.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.bridge_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.bridge_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3BridgeNetDevice(NS3BaseNetDevice): + _rtype = "ns3::BridgeNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_mtu = Attribute("Mtu", + "The MAC-level Maximum Transmission Unit", + type = Types.Integer, + default = "1500", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + attr_enablelearning = Attribute("EnableLearning", + "Enable the learning mode of the Learning Bridge", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_enablelearning) + + attr_expirationtime = Attribute("ExpirationTime", + "Time it takes for learned MAC state entry to expire.", + type = Types.String, + default = "+300000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_expirationtime) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3BridgeNetDevice, self).__init__(ec, guid) + self._home = "ns3-bridge-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bulk_send_application.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bulk_send_application.html new file mode 100644 index 00000000..ecefa443 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bulk_send_application.html @@ -0,0 +1,196 @@ + + + + + + + + nepi.resources.ns3.classes.bulk_send_application — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.bulk_send_application

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3application import NS3BaseApplication 
    +
    +@clsinit_copy
    +
    [docs]class NS3BulkSendApplication(NS3BaseApplication): + _rtype = "ns3::BulkSendApplication" + + @classmethod + def _register_attributes(cls): + + attr_sendsize = Attribute("SendSize", + "The amount of data to send each time.", + type = Types.Integer, + default = "512", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_sendsize) + + attr_remote = Attribute("Remote", + "The address of the destination", + type = Types.String, + default = "00-00-00", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_remote) + + attr_maxbytes = Attribute("MaxBytes", + "The total number of bytes to send. Once these bytes are sent, no data is sent again. The value zero means that there is no limit.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxbytes) + + attr_protocol = Attribute("Protocol", + "The type of protocol to use.", + type = Types.String, + default = "ns3::TcpSocketFactory", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_protocol) + + attr_starttime = Attribute("StartTime", + "Time at which the application will start", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_starttime) + + attr_stoptime = Attribute("StopTime", + "Time at which the application will stop", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stoptime) + + + + @classmethod + def _register_traces(cls): + + tx = Trace("Tx", "A new packet is created and is sent") + + cls._register_trace(tx) + + + + def __init__(self, ec, guid): + super(NS3BulkSendApplication, self).__init__(ec, guid) + self._home = "ns3-bulk-send-application-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/burst_error_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/burst_error_model.html new file mode 100644 index 00000000..a26a704e --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/burst_error_model.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.classes.burst_error_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.burst_error_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3BurstErrorModel(NS3BaseErrorModel): + _rtype = "ns3::BurstErrorModel" + + @classmethod + def _register_attributes(cls): + + attr_errorrate = Attribute("ErrorRate", + "The burst error event.", + type = Types.Double, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_errorrate) + + attr_burststart = Attribute("BurstStart", + "The decision variable attached to this error model.", + type = Types.String, + default = "ns3::UniformRandomVariable[Min=0.0|Max=1.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_burststart) + + attr_burstsize = Attribute("BurstSize", + "The number of packets being corrupted at one drop.", + type = Types.String, + default = "ns3::UniformRandomVariable[Min=1|Max=4]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_burstsize) + + attr_isenabled = Attribute("IsEnabled", + "Whether this ErrorModel is enabled or not.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_isenabled) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3BurstErrorModel, self).__init__(ec, guid) + self._home = "ns3-burst-error-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cara_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cara_wifi_manager.html new file mode 100644 index 00000000..36191fdb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cara_wifi_manager.html @@ -0,0 +1,258 @@ + + + + + + + + nepi.resources.ns3.classes.cara_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.cara_wifi_manager

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
    +
    +@clsinit_copy
    +
    [docs]class NS3CaraWifiManager(NS3BaseWifiRemoteStationManager): + _rtype = "ns3::CaraWifiManager" + + @classmethod + def _register_attributes(cls): + + attr_probethreshold = Attribute("ProbeThreshold", + "The number of consecutive transmissions failure to activate the RTS probe.", + type = Types.Integer, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_probethreshold) + + attr_failurethreshold = Attribute("FailureThreshold", + "The number of consecutive transmissions failure to decrease the rate.", + type = Types.Integer, + default = "2", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_failurethreshold) + + attr_successthreshold = Attribute("SuccessThreshold", + "The minimum number of sucessfull transmissions to try a new rate.", + type = Types.Integer, + default = "10", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_successthreshold) + + attr_timeout = Attribute("Timeout", + "The \'timer\' in the CARA algorithm", + type = Types.Integer, + default = "15", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_timeout) + + attr_islowlatency = Attribute("IsLowLatency", + "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_islowlatency) + + attr_maxssrc = Attribute("MaxSsrc", + "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxssrc) + + attr_maxslrc = Attribute("MaxSlrc", + "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxslrc) + + attr_rtsctsthreshold = Attribute("RtsCtsThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2012, Section 9.3.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rtsctsthreshold) + + attr_fragmentationthreshold = Attribute("FragmentationThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2012, Section 9.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentationthreshold) + + attr_nonunicastmode = Attribute("NonUnicastMode", + "Wifi mode used for non-unicast transmissions.", + type = Types.String, + default = "Invalid-WifiMode", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_nonunicastmode) + + attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel", + "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaulttxpowerlevel) + + + + @classmethod + def _register_traces(cls): + + mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed") + + cls._register_trace(mactxrtsfailed) + + mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed") + + cls._register_trace(mactxdatafailed) + + mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinalrtsfailed) + + mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinaldatafailed) + + + + def __init__(self, ec, guid): + super(NS3CaraWifiManager, self).__init__(ec, guid) + self._home = "ns3-cara-wifi-manager-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_acceleration_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_acceleration_mobility_model.html new file mode 100644 index 00000000..409cdba1 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_acceleration_mobility_model.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.constant_acceleration_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.constant_acceleration_mobility_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3ConstantAccelerationMobilityModel(NS3BaseMobilityModel): + _rtype = "ns3::ConstantAccelerationMobilityModel" + + @classmethod + def _register_attributes(cls): + + attr_position = Attribute("Position", + "The current position of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved) + + cls._register_attribute(attr_position) + + attr_velocity = Attribute("Velocity", + "The current velocity of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_velocity) + + + + @classmethod + def _register_traces(cls): + + coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed") + + cls._register_trace(coursechange) + + + + def __init__(self, ec, guid): + super(NS3ConstantAccelerationMobilityModel, self).__init__(ec, guid) + self._home = "ns3-constant-acceleration-mobility-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_position_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_position_mobility_model.html new file mode 100644 index 00000000..b45b8b94 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_position_mobility_model.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.constant_position_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.constant_position_mobility_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3ConstantPositionMobilityModel(NS3BaseMobilityModel): + _rtype = "ns3::ConstantPositionMobilityModel" + + @classmethod + def _register_attributes(cls): + + attr_position = Attribute("Position", + "The current position of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved) + + cls._register_attribute(attr_position) + + attr_velocity = Attribute("Velocity", + "The current velocity of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_velocity) + + + + @classmethod + def _register_traces(cls): + + coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed") + + cls._register_trace(coursechange) + + + + def __init__(self, ec, guid): + super(NS3ConstantPositionMobilityModel, self).__init__(ec, guid) + self._home = "ns3-constant-position-mobility-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_rate_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_rate_wifi_manager.html new file mode 100644 index 00000000..5fd39789 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_rate_wifi_manager.html @@ -0,0 +1,238 @@ + + + + + + + + nepi.resources.ns3.classes.constant_rate_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.constant_rate_wifi_manager

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
    +
    +@clsinit_copy
    +
    [docs]class NS3ConstantRateWifiManager(NS3BaseWifiRemoteStationManager): + _rtype = "ns3::ConstantRateWifiManager" + + @classmethod + def _register_attributes(cls): + + attr_datamode = Attribute("DataMode", + "The transmission mode to use for every data packet transmission", + type = Types.String, + default = "OfdmRate6Mbps", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_datamode) + + attr_controlmode = Attribute("ControlMode", + "The transmission mode to use for every control packet transmission.", + type = Types.String, + default = "OfdmRate6Mbps", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_controlmode) + + attr_islowlatency = Attribute("IsLowLatency", + "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_islowlatency) + + attr_maxssrc = Attribute("MaxSsrc", + "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxssrc) + + attr_maxslrc = Attribute("MaxSlrc", + "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxslrc) + + attr_rtsctsthreshold = Attribute("RtsCtsThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2012, Section 9.3.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rtsctsthreshold) + + attr_fragmentationthreshold = Attribute("FragmentationThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2012, Section 9.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentationthreshold) + + attr_nonunicastmode = Attribute("NonUnicastMode", + "Wifi mode used for non-unicast transmissions.", + type = Types.String, + default = "Invalid-WifiMode", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_nonunicastmode) + + attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel", + "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaulttxpowerlevel) + + + + @classmethod + def _register_traces(cls): + + mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed") + + cls._register_trace(mactxrtsfailed) + + mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed") + + cls._register_trace(mactxdatafailed) + + mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinalrtsfailed) + + mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinaldatafailed) + + + + def __init__(self, ec, guid): + super(NS3ConstantRateWifiManager, self).__init__(ec, guid) + self._home = "ns3-constant-rate-wifi-manager-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_speed_propagation_delay_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_speed_propagation_delay_model.html new file mode 100644 index 00000000..a2c6d187 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_speed_propagation_delay_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.constant_speed_propagation_delay_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.constant_speed_propagation_delay_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationdelaymodel import NS3BasePropagationDelayModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3ConstantSpeedPropagationDelayModel(NS3BasePropagationDelayModel): + _rtype = "ns3::ConstantSpeedPropagationDelayModel" + + @classmethod + def _register_attributes(cls): + + attr_speed = Attribute("Speed", + "The speed (m/s)", + type = Types.Double, + default = "3e+08", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_speed) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3ConstantSpeedPropagationDelayModel, self).__init__(ec, guid) + self._home = "ns3-constant-speed-propagation-delay-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_velocity_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_velocity_mobility_model.html new file mode 100644 index 00000000..45650da0 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_velocity_mobility_model.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.constant_velocity_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.constant_velocity_mobility_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3ConstantVelocityMobilityModel(NS3BaseMobilityModel): + _rtype = "ns3::ConstantVelocityMobilityModel" + + @classmethod + def _register_attributes(cls): + + attr_position = Attribute("Position", + "The current position of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved) + + cls._register_attribute(attr_position) + + attr_velocity = Attribute("Velocity", + "The current velocity of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_velocity) + + + + @classmethod + def _register_traces(cls): + + coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed") + + cls._register_trace(coursechange) + + + + def __init__(self, ec, guid): + super(NS3ConstantVelocityMobilityModel, self).__init__(ec, guid) + self._home = "ns3-constant-velocity-mobility-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cost231propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cost231propagation_loss_model.html new file mode 100644 index 00000000..c4c78c5a --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cost231propagation_loss_model.html @@ -0,0 +1,181 @@ + + + + + + + + nepi.resources.ns3.classes.cost231propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.cost231propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3Cost231PropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::Cost231PropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_lambda = Attribute("Lambda", + "The wavelength (default is 2.3 GHz at 300 000 km/s).", + type = Types.Double, + default = "0.130435", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_lambda) + + attr_frequency = Attribute("Frequency", + "The Frequency (default is 2.3 GHz).", + type = Types.Double, + default = "2.3e+09", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_frequency) + + attr_bsantennaheight = Attribute("BSAntennaHeight", + " BS Antenna Height (default is 50m).", + type = Types.Double, + default = "50", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_bsantennaheight) + + attr_ssantennaheight = Attribute("SSAntennaHeight", + " SS Antenna Height (default is 3m).", + type = Types.Double, + default = "3", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ssantennaheight) + + attr_mindistance = Attribute("MinDistance", + "The distance under which the propagation model refuses to give results (m) ", + type = Types.Double, + default = "0.5", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mindistance) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3Cost231PropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-cost231propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_channel.html new file mode 100644 index 00000000..9f64900b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_channel.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.csma_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.csma_channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3channel import NS3BaseChannel 
    +
    +@clsinit_copy
    +
    [docs]class NS3CsmaChannel(NS3BaseChannel): + _rtype = "ns3::CsmaChannel" + + @classmethod + def _register_attributes(cls): + + attr_datarate = Attribute("DataRate", + "The transmission data rate to be provided to devices connected to the channel", + type = Types.String, + default = "4294967295bps", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_datarate) + + attr_delay = Attribute("Delay", + "Transmission delay through the channel", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_delay) + + attr_id = Attribute("Id", + "The id (unique integer) of this Channel.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_id) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3CsmaChannel, self).__init__(ec, guid) + self._home = "ns3-csma-channel-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_net_device.html new file mode 100644 index 00000000..5670af2b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_net_device.html @@ -0,0 +1,220 @@ + + + + + + + + nepi.resources.ns3.classes.csma_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.csma_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3CsmaNetDevice(NS3BaseNetDevice): + _rtype = "ns3::CsmaNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_address = Attribute("Address", + "The MAC address of this device.", + type = Types.String, + default = "ff:ff:ff:ff:ff:ff", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_address) + + attr_mtu = Attribute("Mtu", + "The MAC-level Maximum Transmission Unit", + type = Types.Integer, + default = "1500", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + attr_sendenable = Attribute("SendEnable", + "Enable or disable the transmitter section of the device.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_sendenable) + + attr_receiveenable = Attribute("ReceiveEnable", + "Enable or disable the receiver section of the device.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_receiveenable) + + + + @classmethod + def _register_traces(cls): + + mactx = Trace("MacTx", "Trace source indicating a packet has arrived for transmission by this device") + + cls._register_trace(mactx) + + mactxdrop = Trace("MacTxDrop", "Trace source indicating a packet has been dropped by the device before transmission") + + cls._register_trace(mactxdrop) + + macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(macpromiscrx) + + macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(macrx) + + mactxbackoff = Trace("MacTxBackoff", "Trace source indicating a packet has been delayed by the CSMA backoff process") + + cls._register_trace(mactxbackoff) + + phytxbegin = Trace("PhyTxBegin", "Trace source indicating a packet has begun transmitting over the channel") + + cls._register_trace(phytxbegin) + + phytxend = Trace("PhyTxEnd", "Trace source indicating a packet has been completely transmitted over the channel") + + cls._register_trace(phytxend) + + phytxdrop = Trace("PhyTxDrop", "Trace source indicating a packet has been dropped by the device during transmission") + + cls._register_trace(phytxdrop) + + phyrxend = Trace("PhyRxEnd", "Trace source indicating a packet has been completely received by the device") + + cls._register_trace(phyrxend) + + phyrxdrop = Trace("PhyRxDrop", "Trace source indicating a packet has been dropped by the device during reception") + + cls._register_trace(phyrxdrop) + + sniffer = Trace("Sniffer", "Trace source simulating a non-promiscuous packet sniffer attached to the device") + + cls._register_trace(sniffer) + + promiscsniffer = Trace("PromiscSniffer", "Trace source simulating a promiscuous packet sniffer attached to the device") + + cls._register_trace(promiscsniffer) + + + + def __init__(self, ec, guid): + super(NS3CsmaNetDevice, self).__init__(ec, guid) + self._home = "ns3-csma-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/drop_tail_queue.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/drop_tail_queue.html new file mode 100644 index 00000000..bad4da12 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/drop_tail_queue.html @@ -0,0 +1,164 @@ + + + + + + + + nepi.resources.ns3.classes.drop_tail_queue — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.drop_tail_queue

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3queue import NS3BaseQueue 
    +
    +@clsinit_copy
    +
    [docs]class NS3DropTailQueue(NS3BaseQueue): + _rtype = "ns3::DropTailQueue" + + @classmethod + def _register_attributes(cls): + + attr_maxpackets = Attribute("MaxPackets", + "The maximum number of packets accepted by this DropTailQueue.", + type = Types.Integer, + default = "100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxpackets) + + attr_maxbytes = Attribute("MaxBytes", + "The maximum number of bytes accepted by this DropTailQueue.", + type = Types.Integer, + default = "6553500", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxbytes) + + + + @classmethod + def _register_traces(cls): + + enqueue = Trace("Enqueue", "Enqueue a packet in the queue.") + + cls._register_trace(enqueue) + + dequeue = Trace("Dequeue", "Dequeue a packet from the queue.") + + cls._register_trace(dequeue) + + drop = Trace("Drop", "Drop a packet stored in the queue.") + + cls._register_trace(drop) + + + + def __init__(self, ec, guid): + super(NS3DropTailQueue, self).__init__(ec, guid) + self._home = "ns3-drop-tail-queue-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/dsrdsr_routing.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/dsrdsr_routing.html new file mode 100644 index 00000000..624d037c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/dsrdsr_routing.html @@ -0,0 +1,540 @@ + + + + + + + + nepi.resources.ns3.classes.dsrdsr_routing — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.dsrdsr_routing

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3dsrDsrRouting(NS3Base): + _rtype = "ns3::dsr::DsrRouting" + + @classmethod + def _register_attributes(cls): + + attr_maxsendbufflen = Attribute("MaxSendBuffLen", + "Maximum number of packets that can be stored in send buffer.", + type = Types.Integer, + default = "64", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxsendbufflen) + + attr_maxsendbufftime = Attribute("MaxSendBuffTime", + "Maximum time packets can be queued in the send buffer .", + type = Types.String, + default = "+30000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxsendbufftime) + + attr_maxmaintlen = Attribute("MaxMaintLen", + "Maximum number of packets that can be stored in maintenance buffer.", + type = Types.Integer, + default = "50", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxmaintlen) + + attr_maxmainttime = Attribute("MaxMaintTime", + "Maximum time packets can be queued in maintenance buffer.", + type = Types.String, + default = "+30000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxmainttime) + + attr_maxcachelen = Attribute("MaxCacheLen", + "Maximum number of route entries that can be stored in route cache.", + type = Types.Integer, + default = "64", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxcachelen) + + attr_routecachetimeout = Attribute("RouteCacheTimeout", + "Maximum time the route cache can be queued in route cache.", + type = Types.String, + default = "+300000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_routecachetimeout) + + attr_maxentrieseachdst = Attribute("MaxEntriesEachDst", + "Maximum number of route entries for a single destination to respond.", + type = Types.Integer, + default = "20", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxentrieseachdst) + + attr_sendbuffinterval = Attribute("SendBuffInterval", + "How often to check send buffer for packet with route.", + type = Types.String, + default = "+500000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_sendbuffinterval) + + attr_nodetraversaltime = Attribute("NodeTraversalTime", + "The time it takes to traverse two neighboring nodes.", + type = Types.String, + default = "+40000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_nodetraversaltime) + + attr_rreqretries = Attribute("RreqRetries", + "Maximum number of retransmissions for request discovery of a route.", + type = Types.Integer, + default = "16", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rreqretries) + + attr_maintenanceretries = Attribute("MaintenanceRetries", + "Maximum number of retransmissions for data packets from maintenance buffer.", + type = Types.Integer, + default = "2", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maintenanceretries) + + attr_requesttablesize = Attribute("RequestTableSize", + "Maximum number of request entries in the request table, set this as the number of nodes in the simulation.", + type = Types.Integer, + default = "64", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_requesttablesize) + + attr_requestidsize = Attribute("RequestIdSize", + "Maximum number of request source Ids in the request table.", + type = Types.Integer, + default = "16", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_requestidsize) + + attr_uniquerequestidsize = Attribute("UniqueRequestIdSize", + "Maximum number of request Ids in the request table for a single destination.", + type = Types.Integer, + default = "256", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_uniquerequestidsize) + + attr_nonproprequesttimeout = Attribute("NonPropRequestTimeout", + "The timeout value for non-propagation request.", + type = Types.String, + default = "+30000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_nonproprequesttimeout) + + attr_discoveryhoplimit = Attribute("DiscoveryHopLimit", + "The max discovery hop limit for route requests.", + type = Types.Integer, + default = "255", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_discoveryhoplimit) + + attr_maxsalvagecount = Attribute("MaxSalvageCount", + "The max salvage count for a single data packet.", + type = Types.Integer, + default = "15", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxsalvagecount) + + attr_blacklisttimeout = Attribute("BlacklistTimeout", + "The time for a neighbor to stay in blacklist.", + type = Types.String, + default = "+3000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_blacklisttimeout) + + attr_gratreplyholdoff = Attribute("GratReplyHoldoff", + "The time for gratuitous reply entry to expire.", + type = Types.String, + default = "+1000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_gratreplyholdoff) + + attr_broadcastjitter = Attribute("BroadcastJitter", + "The jitter time to avoid collision for broadcast packets.", + type = Types.Integer, + default = "10", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_broadcastjitter) + + attr_linkacktimeout = Attribute("LinkAckTimeout", + "The time a packet in maintenance buffer wait for link acknowledgment.", + type = Types.String, + default = "+100000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_linkacktimeout) + + attr_trylinkacks = Attribute("TryLinkAcks", + "The number of link acknowledgment to use.", + type = Types.Integer, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_trylinkacks) + + attr_passiveacktimeout = Attribute("PassiveAckTimeout", + "The time a packet in maintenance buffer wait for passive acknowledgment.", + type = Types.String, + default = "+100000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_passiveacktimeout) + + attr_trypassiveacks = Attribute("TryPassiveAcks", + "The number of passive acknowledgment to use.", + type = Types.Integer, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_trypassiveacks) + + attr_requestperiod = Attribute("RequestPeriod", + "The base time interval between route requests.", + type = Types.String, + default = "+500000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_requestperiod) + + attr_maxrequestperiod = Attribute("MaxRequestPeriod", + "The max time interval between route requests.", + type = Types.String, + default = "+10000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxrequestperiod) + + attr_grareplytablesize = Attribute("GraReplyTableSize", + "The gratuitous reply table size.", + type = Types.Integer, + default = "64", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_grareplytablesize) + + attr_cachetype = Attribute("CacheType", + "Use Link Cache or use Path Cache", + type = Types.String, + default = "LinkCache", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_cachetype) + + attr_stabilitydecrfactor = Attribute("StabilityDecrFactor", + "The stability decrease factor for link cache", + type = Types.Integer, + default = "2", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stabilitydecrfactor) + + attr_stabilityincrfactor = Attribute("StabilityIncrFactor", + "The stability increase factor for link cache", + type = Types.Integer, + default = "4", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stabilityincrfactor) + + attr_initstability = Attribute("InitStability", + "The initial stability factor for link cache", + type = Types.String, + default = "+25000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_initstability) + + attr_minlifetime = Attribute("MinLifeTime", + "The minimal life time for link cache", + type = Types.String, + default = "+1000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_minlifetime) + + attr_useextends = Attribute("UseExtends", + "The extension time for link cache", + type = Types.String, + default = "+120000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_useextends) + + attr_enablesubroute = Attribute("EnableSubRoute", + "Enables saving of sub route when receiving route error messages, only available when using path route cache", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_enablesubroute) + + attr_retransincr = Attribute("RetransIncr", + "The increase time for retransmission timer when facing network congestion", + type = Types.String, + default = "+20000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_retransincr) + + attr_maxnetworkqueuesize = Attribute("MaxNetworkQueueSize", + "The max number of packet to save in the network queue.", + type = Types.Integer, + default = "400", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxnetworkqueuesize) + + attr_maxnetworkqueuedelay = Attribute("MaxNetworkQueueDelay", + "The max time for a packet to stay in the network queue.", + type = Types.String, + default = "+30000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxnetworkqueuedelay) + + attr_numpriorityqueues = Attribute("NumPriorityQueues", + "The max number of packet to save in the network queue.", + type = Types.Integer, + default = "2", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_numpriorityqueues) + + attr_linkacknowledgment = Attribute("LinkAcknowledgment", + "Enable Link layer acknowledgment mechanism", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_linkacknowledgment) + + attr_protocolnumber = Attribute("ProtocolNumber", + "The Ip protocol number.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_protocolnumber) + + + + @classmethod + def _register_traces(cls): + + tx = Trace("Tx", "Send DSR packet.") + + cls._register_trace(tx) + + drop = Trace("Drop", "Drop DSR packet") + + cls._register_trace(drop) + + + + def __init__(self, ec, guid): + super(NS3dsrDsrRouting, self).__init__(ec, guid) + self._home = "ns3-dsr-dsr-routing-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/emu_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/emu_net_device.html new file mode 100644 index 00000000..e205dcc3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/emu_net_device.html @@ -0,0 +1,216 @@ + + + + + + + + nepi.resources.ns3.classes.emu_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.emu_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3EmuNetDevice(NS3BaseNetDevice): + _rtype = "ns3::EmuNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_mtu = Attribute("Mtu", + "The MAC-level Maximum Transmission Unit", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + attr_address = Attribute("Address", + "The ns-3 MAC address of this (virtual) device.", + type = Types.String, + default = "ff:ff:ff:ff:ff:ff", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_address) + + attr_devicename = Attribute("DeviceName", + "The name of the underlying real device (e.g. eth1).", + type = Types.String, + default = "eth1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_devicename) + + attr_start = Attribute("Start", + "The simulation time at which to spin up the device thread.", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_start) + + attr_stop = Attribute("Stop", + "The simulation time at which to tear down the device thread.", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stop) + + attr_rxqueuesize = Attribute("RxQueueSize", + "Maximum size of the read queue. This value limits number of packets that have been read from the network into a memory buffer but have not yet been processed by the simulator.", + type = Types.Integer, + default = "1000", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rxqueuesize) + + + + @classmethod + def _register_traces(cls): + + mactx = Trace("MacTx", "Trace source indicating a packet has arrived for transmission by this device") + + cls._register_trace(mactx) + + mactxdrop = Trace("MacTxDrop", "Trace source indicating a packet has been dropped by the device before transmission") + + cls._register_trace(mactxdrop) + + macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(macpromiscrx) + + macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(macrx) + + sniffer = Trace("Sniffer", "Trace source simulating a non-promiscuous packet sniffer attached to the device") + + cls._register_trace(sniffer) + + promiscsniffer = Trace("PromiscSniffer", "Trace source simulating a promiscuous packet sniffer attached to the device") + + cls._register_trace(promiscsniffer) + + + + def __init__(self, ec, guid): + super(NS3EmuNetDevice, self).__init__(ec, guid) + self._home = "ns3-emu-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel.html new file mode 100644 index 00000000..ad325985 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.error_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.error_channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3channel import NS3BaseChannel 
    +
    +@clsinit_copy
    +
    [docs]class NS3ErrorChannel(NS3BaseChannel): + _rtype = "ns3::ErrorChannel" + + @classmethod + def _register_attributes(cls): + + attr_id = Attribute("Id", + "The id (unique integer) of this Channel.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_id) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3ErrorChannel, self).__init__(ec, guid) + self._home = "ns3-error-channel-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel_sixlow.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel_sixlow.html new file mode 100644 index 00000000..bb9ca4fd --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel_sixlow.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.error_channel_sixlow — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.error_channel_sixlow

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3channel import NS3BaseChannel 
    +
    +@clsinit_copy
    +
    [docs]class NS3ErrorChannelSixlow(NS3BaseChannel): + _rtype = "ns3::ErrorChannelSixlow" + + @classmethod + def _register_attributes(cls): + + attr_id = Attribute("Id", + "The id (unique integer) of this Channel.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_id) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3ErrorChannelSixlow, self).__init__(ec, guid) + self._home = "ns3-error-channel-sixlow-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_net_device.html new file mode 100644 index 00000000..8a3f20c5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_net_device.html @@ -0,0 +1,135 @@ + + + + + + + + nepi.resources.ns3.classes.error_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.error_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3ErrorNetDevice(NS3BaseNetDevice): + _rtype = "ns3::ErrorNetDevice" + + @classmethod + def _register_attributes(cls): + pass + + @classmethod + def _register_traces(cls): + + phyrxdrop = Trace("PhyRxDrop", "Trace source indicating a packet has been dropped by the device during reception") + + cls._register_trace(phyrxdrop) + + + + def __init__(self, ec, guid): + super(NS3ErrorNetDevice, self).__init__(ec, guid) + self._home = "ns3-error-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fd_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fd_net_device.html new file mode 100644 index 00000000..53f07363 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fd_net_device.html @@ -0,0 +1,206 @@ + + + + + + + + nepi.resources.ns3.classes.fd_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.fd_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3FdNetDevice(NS3BaseFdNetDevice): + _rtype = "ns3::FdNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_address = Attribute("Address", + "The MAC address of this device.", + type = Types.String, + default = "ff:ff:ff:ff:ff:ff", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_address) + + attr_start = Attribute("Start", + "The simulation time at which to spin up the device thread.", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_start) + + attr_stop = Attribute("Stop", + "The simulation time at which to tear down the device thread.", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stop) + + attr_encapsulationmode = Attribute("EncapsulationMode", + "The link-layer encapsulation type to use.", + type = Types.Enumerate, + default = "Dix", + allowed = ["Dix","Llc","DixPi"], + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_encapsulationmode) + + attr_rxqueuesize = Attribute("RxQueueSize", + "Maximum size of the read queue. This value limits number of packets that have been read from the network into a memory buffer but have not yet been processed by the simulator.", + type = Types.Integer, + default = "1000", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rxqueuesize) + + + + @classmethod + def _register_traces(cls): + + mactx = Trace("MacTx", "Trace source indicating a packet has arrived for transmission by this device") + + cls._register_trace(mactx) + + mactxdrop = Trace("MacTxDrop", "Trace source indicating a packet has been dropped by the device before transmission") + + cls._register_trace(mactxdrop) + + macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(macpromiscrx) + + macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(macrx) + + sniffer = Trace("Sniffer", "Trace source simulating a non-promiscuous packet sniffer attached to the device") + + cls._register_trace(sniffer) + + promiscsniffer = Trace("PromiscSniffer", "Trace source simulating a promiscuous packet sniffer attached to the device") + + cls._register_trace(promiscsniffer) + + + + def __init__(self, ec, guid): + super(NS3FdNetDevice, self).__init__(ec, guid) + self._home = "ns3-fd-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fixed_rss_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fixed_rss_loss_model.html new file mode 100644 index 00000000..4fb94ab4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fixed_rss_loss_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.fixed_rss_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.fixed_rss_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3FixedRssLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::FixedRssLossModel" + + @classmethod + def _register_attributes(cls): + + attr_rss = Attribute("Rss", + "The fixed receiver Rss.", + type = Types.Double, + default = "-150", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rss) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3FixedRssLossModel, self).__init__(ec, guid) + self._home = "ns3-fixed-rss-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/friis_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/friis_propagation_loss_model.html new file mode 100644 index 00000000..abf162de --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/friis_propagation_loss_model.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.friis_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.friis_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3FriisPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::FriisPropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_frequency = Attribute("Frequency", + "The carrier frequency (in Hz) at which propagation occurs (default is 5.15 GHz).", + type = Types.Double, + default = "5.15e+09", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_frequency) + + attr_systemloss = Attribute("SystemLoss", + "The system loss", + type = Types.Double, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_systemloss) + + attr_minloss = Attribute("MinLoss", + "The minimum value (dB) of the total loss, used at short ranges. Note: ", + type = Types.Double, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_minloss) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3FriisPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-friis-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/gauss_markov_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/gauss_markov_mobility_model.html new file mode 100644 index 00000000..ed9bcb2d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/gauss_markov_mobility_model.html @@ -0,0 +1,246 @@ + + + + + + + + nepi.resources.ns3.classes.gauss_markov_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.gauss_markov_mobility_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3GaussMarkovMobilityModel(NS3BaseMobilityModel): + _rtype = "ns3::GaussMarkovMobilityModel" + + @classmethod + def _register_attributes(cls): + + attr_bounds = Attribute("Bounds", + "Bounds of the area to cruise.", + type = Types.String, + default = "-100|100|-100|100|0|100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_bounds) + + attr_timestep = Attribute("TimeStep", + "Change current direction and speed after moving for this time.", + type = Types.String, + default = "+1000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_timestep) + + attr_alpha = Attribute("Alpha", + "A constant representing the tunable parameter in the Gauss-Markov model.", + type = Types.Double, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_alpha) + + attr_meanvelocity = Attribute("MeanVelocity", + "A random variable used to assign the average velocity.", + type = Types.String, + default = "ns3::UniformRandomVariable[Min=0.0|Max=1.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_meanvelocity) + + attr_meandirection = Attribute("MeanDirection", + "A random variable used to assign the average direction.", + type = Types.String, + default = "ns3::UniformRandomVariable[Min=0.0|Max=6.283185307]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_meandirection) + + attr_meanpitch = Attribute("MeanPitch", + "A random variable used to assign the average pitch.", + type = Types.String, + default = "ns3::ConstantRandomVariable[Constant=0.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_meanpitch) + + attr_normalvelocity = Attribute("NormalVelocity", + "A gaussian random variable used to calculate the next velocity value.", + type = Types.String, + default = "ns3::NormalRandomVariable[Mean=0.0|Variance=1.0|Bound=10.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_normalvelocity) + + attr_normaldirection = Attribute("NormalDirection", + "A gaussian random variable used to calculate the next direction value.", + type = Types.String, + default = "ns3::NormalRandomVariable[Mean=0.0|Variance=1.0|Bound=10.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_normaldirection) + + attr_normalpitch = Attribute("NormalPitch", + "A gaussian random variable used to calculate the next pitch value.", + type = Types.String, + default = "ns3::NormalRandomVariable[Mean=0.0|Variance=1.0|Bound=10.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_normalpitch) + + attr_position = Attribute("Position", + "The current position of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved) + + cls._register_attribute(attr_position) + + attr_velocity = Attribute("Velocity", + "The current velocity of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_velocity) + + + + @classmethod + def _register_traces(cls): + + coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed") + + cls._register_trace(coursechange) + + + + def __init__(self, ec, guid): + super(NS3GaussMarkovMobilityModel, self).__init__(ec, guid) + self._home = "ns3-gauss-markov-mobility-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hierarchical_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hierarchical_mobility_model.html new file mode 100644 index 00000000..a6c94cab --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hierarchical_mobility_model.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.hierarchical_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.hierarchical_mobility_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3HierarchicalMobilityModel(NS3BaseMobilityModel): + _rtype = "ns3::HierarchicalMobilityModel" + + @classmethod + def _register_attributes(cls): + + attr_position = Attribute("Position", + "The current position of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved) + + cls._register_attribute(attr_position) + + attr_velocity = Attribute("Velocity", + "The current velocity of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_velocity) + + + + @classmethod + def _register_traces(cls): + + coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed") + + cls._register_trace(coursechange) + + + + def __init__(self, ec, guid): + super(NS3HierarchicalMobilityModel, self).__init__(ec, guid) + self._home = "ns3-hierarchical-mobility-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hybrid_buildings_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hybrid_buildings_propagation_loss_model.html new file mode 100644 index 00000000..df1a68c1 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hybrid_buildings_propagation_loss_model.html @@ -0,0 +1,181 @@ + + + + + + + + nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3HybridBuildingsPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::HybridBuildingsPropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_los2nlosthr = Attribute("Los2NlosThr", + " Threshold from LoS to NLoS in ITU 1411 [m].", + type = Types.Double, + default = "200", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_los2nlosthr) + + attr_shadowsigmaoutdoor = Attribute("ShadowSigmaOutdoor", + "Standard deviation of the normal distribution used for calculate the shadowing for outdoor nodes", + type = Types.Double, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_shadowsigmaoutdoor) + + attr_shadowsigmaindoor = Attribute("ShadowSigmaIndoor", + "Standard deviation of the normal distribution used for calculate the shadowing for indoor nodes ", + type = Types.Double, + default = "8", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_shadowsigmaindoor) + + attr_shadowsigmaextwalls = Attribute("ShadowSigmaExtWalls", + "Standard deviation of the normal distribution used for calculate the shadowing due to ext walls ", + type = Types.Double, + default = "5", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_shadowsigmaextwalls) + + attr_internalwallloss = Attribute("InternalWallLoss", + "Additional loss for each internal wall [dB]", + type = Types.Double, + default = "5", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_internalwallloss) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3HybridBuildingsPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-hybrid-buildings-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv4l4protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv4l4protocol.html new file mode 100644 index 00000000..8bf1f9ed --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv4l4protocol.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.icmpv4l4protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.icmpv4l4protocol

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3icmpv4l4protocol import NS3BaseIcmpv4L4Protocol 
    +
    +@clsinit_copy
    +
    [docs]class NS3Icmpv4L4Protocol(NS3BaseIcmpv4L4Protocol): + _rtype = "ns3::Icmpv4L4Protocol" + + @classmethod + def _register_attributes(cls): + + attr_protocolnumber = Attribute("ProtocolNumber", + "The Ip protocol number.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_protocolnumber) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3Icmpv4L4Protocol, self).__init__(ec, guid) + self._home = "ns3-icmpv4l4protocol-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv6l4protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv6l4protocol.html new file mode 100644 index 00000000..951fec48 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv6l4protocol.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.icmpv6l4protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.icmpv6l4protocol

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3Icmpv6L4Protocol(NS3Base): + _rtype = "ns3::Icmpv6L4Protocol" + + @classmethod + def _register_attributes(cls): + + attr_dad = Attribute("DAD", + "Always do DAD check.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_dad) + + attr_solicitationjitter = Attribute("SolicitationJitter", + "The jitter in ms a node is allowed to wait before sending any solicitation . Some jitter aims to prevent collisions. By default, the model will wait for a duration in ms defined by a uniform random-variable between 0 and SolicitationJitter", + type = Types.String, + default = "ns3::UniformRandomVariable[Min=0.0|Max=10.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_solicitationjitter) + + attr_protocolnumber = Attribute("ProtocolNumber", + "The Ip protocol number.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_protocolnumber) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3Icmpv6L4Protocol, self).__init__(ec, guid) + self._home = "ns3-icmpv6l4protocol-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ideal_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ideal_wifi_manager.html new file mode 100644 index 00000000..f23b5f70 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ideal_wifi_manager.html @@ -0,0 +1,228 @@ + + + + + + + + nepi.resources.ns3.classes.ideal_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.ideal_wifi_manager

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
    +
    +@clsinit_copy
    +
    [docs]class NS3IdealWifiManager(NS3BaseWifiRemoteStationManager): + _rtype = "ns3::IdealWifiManager" + + @classmethod + def _register_attributes(cls): + + attr_berthreshold = Attribute("BerThreshold", + "The maximum Bit Error Rate acceptable at any transmission mode", + type = Types.Double, + default = "1e-05", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_berthreshold) + + attr_islowlatency = Attribute("IsLowLatency", + "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_islowlatency) + + attr_maxssrc = Attribute("MaxSsrc", + "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxssrc) + + attr_maxslrc = Attribute("MaxSlrc", + "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxslrc) + + attr_rtsctsthreshold = Attribute("RtsCtsThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2012, Section 9.3.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rtsctsthreshold) + + attr_fragmentationthreshold = Attribute("FragmentationThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2012, Section 9.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentationthreshold) + + attr_nonunicastmode = Attribute("NonUnicastMode", + "Wifi mode used for non-unicast transmissions.", + type = Types.String, + default = "Invalid-WifiMode", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_nonunicastmode) + + attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel", + "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaulttxpowerlevel) + + + + @classmethod + def _register_traces(cls): + + mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed") + + cls._register_trace(mactxrtsfailed) + + mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed") + + cls._register_trace(mactxdatafailed) + + mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinalrtsfailed) + + mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinaldatafailed) + + + + def __init__(self, ec, guid): + super(NS3IdealWifiManager, self).__init__(ec, guid) + self._home = "ns3-ideal-wifi-manager-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ipv4l3protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ipv4l3protocol.html new file mode 100644 index 00000000..1b4d4845 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ipv4l3protocol.html @@ -0,0 +1,206 @@ + + + + + + + + nepi.resources.ns3.classes.ipv4l3protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.ipv4l3protocol

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3ipv4l3protocol import NS3BaseIpv4L3Protocol 
    +
    +@clsinit_copy
    +
    [docs]class NS3Ipv4L3Protocol(NS3BaseIpv4L3Protocol): + _rtype = "ns3::Ipv4L3Protocol" + + @classmethod + def _register_attributes(cls): + + attr_defaulttos = Attribute("DefaultTos", + "The TOS value set by default on all outgoing packets generated on this node.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaulttos) + + attr_defaultttl = Attribute("DefaultTtl", + "The TTL value set by default on all outgoing packets generated on this node.", + type = Types.Integer, + default = "64", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaultttl) + + attr_fragmentexpirationtimeout = Attribute("FragmentExpirationTimeout", + "When this timeout expires, the fragments will be cleared from the buffer.", + type = Types.String, + default = "+30000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentexpirationtimeout) + + attr_ipforward = Attribute("IpForward", + "Globally enable or disable IP forwarding for all current and future Ipv4 devices.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ipforward) + + attr_weakesmodel = Attribute("WeakEsModel", + "RFC1122 term for whether host accepts datagram with a dest. address on another interface", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_weakesmodel) + + + + @classmethod + def _register_traces(cls): + + tx = Trace("Tx", "Send ipv4 packet to outgoing interface.") + + cls._register_trace(tx) + + rx = Trace("Rx", "Receive ipv4 packet from incoming interface.") + + cls._register_trace(rx) + + drop = Trace("Drop", "Drop ipv4 packet") + + cls._register_trace(drop) + + sendoutgoing = Trace("SendOutgoing", "A newly-generated packet by this node is about to be queued for transmission") + + cls._register_trace(sendoutgoing) + + unicastforward = Trace("UnicastForward", "A unicast IPv4 packet was received by this node and is being forwarded to another node") + + cls._register_trace(unicastforward) + + localdeliver = Trace("LocalDeliver", "An IPv4 packet was received by/for this node, and it is being forward up the stack") + + cls._register_trace(localdeliver) + + + + def __init__(self, ec, guid): + super(NS3Ipv4L3Protocol, self).__init__(ec, guid) + self._home = "ns3-ipv4l3protocol-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411los_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411los_propagation_loss_model.html new file mode 100644 index 00000000..dff139d4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411los_propagation_loss_model.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3ItuR1411LosPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::ItuR1411LosPropagationLossModel" + + @classmethod + def _register_attributes(cls): + pass + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3ItuR1411LosPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-itu-r1411los-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411nlos_over_rooftop_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411nlos_over_rooftop_propagation_loss_model.html new file mode 100644 index 00000000..afc6ba30 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411nlos_over_rooftop_propagation_loss_model.html @@ -0,0 +1,201 @@ + + + + + + + + nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3ItuR1411NlosOverRooftopPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::ItuR1411NlosOverRooftopPropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_environment = Attribute("Environment", + "Environment Scenario", + type = Types.Enumerate, + default = "Urban", + allowed = ["Urban","SubUrban","OpenAreas"], + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_environment) + + attr_citysize = Attribute("CitySize", + "Dimension of the city", + type = Types.Enumerate, + default = "Large", + allowed = ["Small","Medium","Large"], + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_citysize) + + attr_rooftoplevel = Attribute("RooftopLevel", + "The height of the rooftop level in meters", + type = Types.Double, + default = "20", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rooftoplevel) + + attr_streetsorientation = Attribute("StreetsOrientation", + "The orientation of streets in degrees [0,90] with respect to the direction of propagation", + type = Types.Double, + default = "45", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_streetsorientation) + + attr_streetswidth = Attribute("StreetsWidth", + "The width of streets", + type = Types.Double, + default = "20", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_streetswidth) + + attr_buildingsextend = Attribute("BuildingsExtend", + "The distance over which the buildings extend", + type = Types.Double, + default = "80", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_buildingsextend) + + attr_buildingseparation = Attribute("BuildingSeparation", + "The separation between buildings", + type = Types.Double, + default = "50", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_buildingseparation) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3ItuR1411NlosOverRooftopPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-itu-r1411nlos-over-rooftop-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/jakes_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/jakes_propagation_loss_model.html new file mode 100644 index 00000000..7848615f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/jakes_propagation_loss_model.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.jakes_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.jakes_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3JakesPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::JakesPropagationLossModel" + + @classmethod + def _register_attributes(cls): + pass + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3JakesPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-jakes-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/kun2600mhz_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/kun2600mhz_propagation_loss_model.html new file mode 100644 index 00000000..8d1f117f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/kun2600mhz_propagation_loss_model.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3Kun2600MhzPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::Kun2600MhzPropagationLossModel" + + @classmethod + def _register_attributes(cls): + pass + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3Kun2600MhzPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-kun2600mhz-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/list_error_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/list_error_model.html new file mode 100644 index 00000000..eaa1c9e5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/list_error_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.list_error_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.list_error_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3ListErrorModel(NS3BaseErrorModel): + _rtype = "ns3::ListErrorModel" + + @classmethod + def _register_attributes(cls): + + attr_isenabled = Attribute("IsEnabled", + "Whether this ErrorModel is enabled or not.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_isenabled) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3ListErrorModel, self).__init__(ec, guid) + self._home = "ns3-list-error-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/log_distance_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/log_distance_propagation_loss_model.html new file mode 100644 index 00000000..aa34c047 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/log_distance_propagation_loss_model.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.log_distance_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.log_distance_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3LogDistancePropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::LogDistancePropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_exponent = Attribute("Exponent", + "The exponent of the Path Loss propagation model", + type = Types.Double, + default = "3", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_exponent) + + attr_referencedistance = Attribute("ReferenceDistance", + "The distance at which the reference loss is calculated (m)", + type = Types.Double, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_referencedistance) + + attr_referenceloss = Attribute("ReferenceLoss", + "The reference loss at reference distance (dB). (Default is Friis at 1m with 5.15 GHz)", + type = Types.Double, + default = "46.6777", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_referenceloss) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3LogDistancePropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-log-distance-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/loopback_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/loopback_net_device.html new file mode 100644 index 00000000..fb9b40ca --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/loopback_net_device.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.loopback_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.loopback_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3LoopbackNetDevice(NS3BaseNetDevice): + _rtype = "ns3::LoopbackNetDevice" + + @classmethod + def _register_attributes(cls): + pass + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3LoopbackNetDevice, self).__init__(ec, guid) + self._home = "ns3-loopback-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lr_wpan_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lr_wpan_net_device.html new file mode 100644 index 00000000..f85e8a87 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lr_wpan_net_device.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.lr_wpan_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.lr_wpan_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3LrWpanNetDevice(NS3BaseNetDevice): + _rtype = "ns3::LrWpanNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_useacks = Attribute("UseAcks", + "Request acknowledgments for data frames.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_useacks) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3LrWpanNetDevice, self).__init__(ec, guid) + self._home = "ns3-lr-wpan-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_enb_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_enb_net_device.html new file mode 100644 index 00000000..61bab79f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_enb_net_device.html @@ -0,0 +1,211 @@ + + + + + + + + nepi.resources.ns3.classes.lte_enb_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.lte_enb_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3LteEnbNetDevice(NS3BaseNetDevice): + _rtype = "ns3::LteEnbNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_ulbandwidth = Attribute("UlBandwidth", + "Uplink Transmission Bandwidth Configuration in number of Resource Blocks", + type = Types.Integer, + default = "25", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ulbandwidth) + + attr_dlbandwidth = Attribute("DlBandwidth", + "Downlink Transmission Bandwidth Configuration in number of Resource Blocks", + type = Types.Integer, + default = "25", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_dlbandwidth) + + attr_cellid = Attribute("CellId", + "Cell Identifier", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_cellid) + + attr_dlearfcn = Attribute("DlEarfcn", + "Downlink E-UTRA Absolute Radio Frequency Channel Number (EARFCN) as per 3GPP 36.101 Section 5.7.3. ", + type = Types.Integer, + default = "100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_dlearfcn) + + attr_ulearfcn = Attribute("UlEarfcn", + "Uplink E-UTRA Absolute Radio Frequency Channel Number (EARFCN) as per 3GPP 36.101 Section 5.7.3. ", + type = Types.Integer, + default = "18100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ulearfcn) + + attr_csgid = Attribute("CsgId", + "The Closed Subscriber Group (CSG) identity that this eNodeB belongs to", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_csgid) + + attr_csgindication = Attribute("CsgIndication", + "If true, only UEs which are members of the CSG (i.e. same CSG ID) can gain access to the eNodeB, therefore enforcing closed access mode. Otherwise, the eNodeB operates as a non-CSG cell and implements open access mode.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_csgindication) + + attr_mtu = Attribute("Mtu", + "The MAC-level Maximum Transmission Unit", + type = Types.Integer, + default = "30000", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3LteEnbNetDevice, self).__init__(ec, guid) + self._home = "ns3-lte-enb-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_simple_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_simple_net_device.html new file mode 100644 index 00000000..69e64841 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_simple_net_device.html @@ -0,0 +1,135 @@ + + + + + + + + nepi.resources.ns3.classes.lte_simple_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.lte_simple_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3LteSimpleNetDevice(NS3BaseNetDevice): + _rtype = "ns3::LteSimpleNetDevice" + + @classmethod + def _register_attributes(cls): + pass + + @classmethod + def _register_traces(cls): + + phyrxdrop = Trace("PhyRxDrop", "Trace source indicating a packet has been dropped by the device during reception") + + cls._register_trace(phyrxdrop) + + + + def __init__(self, ec, guid): + super(NS3LteSimpleNetDevice, self).__init__(ec, guid) + self._home = "ns3-lte-simple-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_ue_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_ue_net_device.html new file mode 100644 index 00000000..2ed03a61 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_ue_net_device.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.classes.lte_ue_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.lte_ue_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3LteUeNetDevice(NS3BaseNetDevice): + _rtype = "ns3::LteUeNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_imsi = Attribute("Imsi", + "International Mobile Subscriber Identity assigned to this UE", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_imsi) + + attr_dlearfcn = Attribute("DlEarfcn", + "Downlink E-UTRA Absolute Radio Frequency Channel Number (EARFCN) as per 3GPP 36.101 Section 5.7.3. ", + type = Types.Integer, + default = "100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_dlearfcn) + + attr_csgid = Attribute("CsgId", + "The Closed Subscriber Group (CSG) identity that this UE is associated with, i.e., giving the UE access to cells which belong to this particular CSG. This restriction only applies to initial cell selection and EPC-enabled simulation. This does not revoke the UE\'s access to non-CSG cells. ", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_csgid) + + attr_mtu = Attribute("Mtu", + "The MAC-level Maximum Transmission Unit", + type = Types.Integer, + default = "30000", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3LteUeNetDevice, self).__init__(ec, guid) + self._home = "ns3-lte-ue-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/matrix_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/matrix_propagation_loss_model.html new file mode 100644 index 00000000..91e9fbe2 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/matrix_propagation_loss_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.matrix_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.matrix_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3MatrixPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::MatrixPropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_defaultloss = Attribute("DefaultLoss", + "The default value for propagation loss, dB.", + type = Types.Double, + default = "1.79769e+308", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaultloss) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3MatrixPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-matrix-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_point_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_point_device.html new file mode 100644 index 00000000..aae79d55 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_point_device.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.mesh_point_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.mesh_point_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3MeshPointDevice(NS3BaseNetDevice): + _rtype = "ns3::MeshPointDevice" + + @classmethod + def _register_attributes(cls): + + attr_mtu = Attribute("Mtu", + "The MAC-level Maximum Transmission Unit", + type = Types.Integer, + default = "65535", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3MeshPointDevice, self).__init__(ec, guid) + self._home = "ns3-mesh-point-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_wifi_interface_mac.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_wifi_interface_mac.html new file mode 100644 index 00000000..87af1d64 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_wifi_interface_mac.html @@ -0,0 +1,330 @@ + + + + + + + + nepi.resources.ns3.classes.mesh_wifi_interface_mac — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.mesh_wifi_interface_mac

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
    +
    +@clsinit_copy
    +
    [docs]class NS3MeshWifiInterfaceMac(NS3BaseWifiMac): + _rtype = "ns3::MeshWifiInterfaceMac" + + @classmethod + def _register_attributes(cls): + + attr_beaconinterval = Attribute("BeaconInterval", + "Beacon Interval", + type = Types.String, + default = "+500000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_beaconinterval) + + attr_randomstart = Attribute("RandomStart", + "Window when beacon generating starts (uniform random) in seconds", + type = Types.String, + default = "+500000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_randomstart) + + attr_beacongeneration = Attribute("BeaconGeneration", + "Enable/Disable Beaconing.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_beacongeneration) + + attr_qossupported = Attribute("QosSupported", + "This Boolean attribute is set to enable 802.11e/WMM-style QoS support at this STA", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_qossupported) + + attr_htsupported = Attribute("HtSupported", + "This Boolean attribute is set to enable 802.11n support at this STA", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_htsupported) + + attr_ctstoselfsupported = Attribute("CtsToSelfSupported", + "Use CTS to Self when using a rate that is not in the basic set rate", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ctstoselfsupported) + + attr_ctstimeout = Attribute("CtsTimeout", + "When this timeout expires, the RTS/CTS handshake has failed.", + type = Types.String, + default = "+75000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ctstimeout) + + attr_acktimeout = Attribute("AckTimeout", + "When this timeout expires, the DATA/ACK handshake has failed.", + type = Types.String, + default = "+75000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_acktimeout) + + attr_basicblockacktimeout = Attribute("BasicBlockAckTimeout", + "When this timeout expires, the BASIC_BLOCK_ACK_REQ/BASIC_BLOCK_ACK handshake has failed.", + type = Types.String, + default = "+281000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_basicblockacktimeout) + + attr_compressedblockacktimeout = Attribute("CompressedBlockAckTimeout", + "When this timeout expires, the COMPRESSED_BLOCK_ACK_REQ/COMPRESSED_BLOCK_ACK handshake has failed.", + type = Types.String, + default = "+107000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_compressedblockacktimeout) + + attr_sifs = Attribute("Sifs", + "The value of the SIFS constant.", + type = Types.String, + default = "+16000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_sifs) + + attr_eifsnodifs = Attribute("EifsNoDifs", + "The value of EIFS-DIFS", + type = Types.String, + default = "+60000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_eifsnodifs) + + attr_slot = Attribute("Slot", + "The duration of a Slot.", + type = Types.String, + default = "+9000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_slot) + + attr_pifs = Attribute("Pifs", + "The value of the PIFS constant.", + type = Types.String, + default = "+25000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pifs) + + attr_rifs = Attribute("Rifs", + "The value of the RIFS constant.", + type = Types.String, + default = "+2000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rifs) + + attr_maxpropagationdelay = Attribute("MaxPropagationDelay", + "The maximum propagation delay. Unused for now.", + type = Types.String, + default = "+3333.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxpropagationdelay) + + attr_ssid = Attribute("Ssid", + "The ssid we want to belong to.", + type = Types.String, + default = "default", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ssid) + + + + @classmethod + def _register_traces(cls): + + txokheader = Trace("TxOkHeader", "The header of successfully transmitted packet") + + cls._register_trace(txokheader) + + txerrheader = Trace("TxErrHeader", "The header of unsuccessfully transmitted packet") + + cls._register_trace(txerrheader) + + mactx = Trace("MacTx", "A packet has been received from higher layers and is being processed in preparation for queueing for transmission.") + + cls._register_trace(mactx) + + mactxdrop = Trace("MacTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.") + + cls._register_trace(mactxdrop) + + macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(macpromiscrx) + + macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(macrx) + + macrxdrop = Trace("MacRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.") + + cls._register_trace(macrxdrop) + + + + def __init__(self, ec, guid): + super(NS3MeshWifiInterfaceMac, self).__init__(ec, guid) + self._home = "ns3-mesh-wifi-interface-mac-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/minstrel_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/minstrel_wifi_manager.html new file mode 100644 index 00000000..2c01269a --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/minstrel_wifi_manager.html @@ -0,0 +1,268 @@ + + + + + + + + nepi.resources.ns3.classes.minstrel_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.minstrel_wifi_manager

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
    +
    +@clsinit_copy
    +
    [docs]class NS3MinstrelWifiManager(NS3BaseWifiRemoteStationManager): + _rtype = "ns3::MinstrelWifiManager" + + @classmethod + def _register_attributes(cls): + + attr_updatestatistics = Attribute("UpdateStatistics", + "The interval between updating statistics table ", + type = Types.String, + default = "+100000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_updatestatistics) + + attr_lookaroundrate = Attribute("LookAroundRate", + "the percentage to try other rates", + type = Types.Double, + default = "10", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_lookaroundrate) + + attr_ewma = Attribute("EWMA", + "EWMA level", + type = Types.Double, + default = "75", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ewma) + + attr_samplecolumn = Attribute("SampleColumn", + "The number of columns used for sampling", + type = Types.Double, + default = "10", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_samplecolumn) + + attr_packetlength = Attribute("PacketLength", + "The packet length used for calculating mode TxTime", + type = Types.Double, + default = "1200", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_packetlength) + + attr_islowlatency = Attribute("IsLowLatency", + "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_islowlatency) + + attr_maxssrc = Attribute("MaxSsrc", + "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxssrc) + + attr_maxslrc = Attribute("MaxSlrc", + "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxslrc) + + attr_rtsctsthreshold = Attribute("RtsCtsThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2012, Section 9.3.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rtsctsthreshold) + + attr_fragmentationthreshold = Attribute("FragmentationThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2012, Section 9.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentationthreshold) + + attr_nonunicastmode = Attribute("NonUnicastMode", + "Wifi mode used for non-unicast transmissions.", + type = Types.String, + default = "Invalid-WifiMode", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_nonunicastmode) + + attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel", + "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaulttxpowerlevel) + + + + @classmethod + def _register_traces(cls): + + mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed") + + cls._register_trace(mactxrtsfailed) + + mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed") + + cls._register_trace(mactxdatafailed) + + mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinalrtsfailed) + + mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinaldatafailed) + + + + def __init__(self, ec, guid): + super(NS3MinstrelWifiManager, self).__init__(ec, guid) + self._home = "ns3-minstrel-wifi-manager-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/multi_model_spectrum_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/multi_model_spectrum_channel.html new file mode 100644 index 00000000..c80bd72b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/multi_model_spectrum_channel.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.multi_model_spectrum_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.multi_model_spectrum_channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3channel import NS3BaseChannel 
    +
    +@clsinit_copy
    +
    [docs]class NS3MultiModelSpectrumChannel(NS3BaseChannel): + _rtype = "ns3::MultiModelSpectrumChannel" + + @classmethod + def _register_attributes(cls): + + attr_maxlossdb = Attribute("MaxLossDb", + "If a single-frequency PropagationLossModel is used, this value represents the maximum loss in dB for which transmissions will be passed to the receiving PHY. Signals for which the PropagationLossModel returns a loss bigger than this value will not be propagated to the receiver. This parameter is to be used to reduce the computational load by not propagating signals that are far beyond the interference range. Note that the default value corresponds to considering all signals for reception. Tune this value with care. ", + type = Types.Double, + default = "1e+09", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxlossdb) + + attr_id = Attribute("Id", + "The id (unique integer) of this Channel.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_id) + + + + @classmethod + def _register_traces(cls): + + pathloss = Trace("PathLoss", "This trace is fired whenever a new path loss value is calculated. The first and second parameters to the trace are pointers respectively to the TX and RX SpectrumPhy instances, whereas the third parameters is the loss value in dB. Note that the loss value reported by this trace is the single-frequency loss value obtained by evaluating only the TX and RX AntennaModels and the PropagationLossModel. In particular, note that SpectrumPropagationLossModel (even if present) is never used to evaluate the loss value reported in this trace. ") + + cls._register_trace(pathloss) + + + + def __init__(self, ec, guid): + super(NS3MultiModelSpectrumChannel, self).__init__(ec, guid) + self._home = "ns3-multi-model-spectrum-channel-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nakagami_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nakagami_propagation_loss_model.html new file mode 100644 index 00000000..17d6e92e --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nakagami_propagation_loss_model.html @@ -0,0 +1,201 @@ + + + + + + + + nepi.resources.ns3.classes.nakagami_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.nakagami_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3NakagamiPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::NakagamiPropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_distance1 = Attribute("Distance1", + "Beginning of the second distance field. Default is 80m.", + type = Types.Double, + default = "80", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_distance1) + + attr_distance2 = Attribute("Distance2", + "Beginning of the third distance field. Default is 200m.", + type = Types.Double, + default = "200", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_distance2) + + attr_m0 = Attribute("m0", + "m0 for distances smaller than Distance1. Default is 1.5.", + type = Types.Double, + default = "1.5", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_m0) + + attr_m1 = Attribute("m1", + "m1 for distances smaller than Distance2. Default is 0.75.", + type = Types.Double, + default = "0.75", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_m1) + + attr_m2 = Attribute("m2", + "m2 for distances greater than Distance2. Default is 0.75.", + type = Types.Double, + default = "0.75", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_m2) + + attr_erlangrv = Attribute("ErlangRv", + "Access to the underlying ErlangRandomVariable", + type = Types.String, + default = "ns3::ErlangRandomVariable", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_erlangrv) + + attr_gammarv = Attribute("GammaRv", + "Access to the underlying GammaRandomVariable", + type = Types.String, + default = "ns3::GammaRandomVariable", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_gammarv) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3NakagamiPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-nakagami-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nist_error_rate_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nist_error_rate_model.html new file mode 100644 index 00000000..d6924009 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nist_error_rate_model.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.nist_error_rate_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.nist_error_rate_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3errorratemodel import NS3BaseErrorRateModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3NistErrorRateModel(NS3BaseErrorRateModel): + _rtype = "ns3::NistErrorRateModel" + + @classmethod + def _register_attributes(cls): + pass + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3NistErrorRateModel, self).__init__(ec, guid) + self._home = "ns3-nist-error-rate-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/node.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/node.html new file mode 100644 index 00000000..dfc75d30 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/node.html @@ -0,0 +1,151 @@ + + + + + + + + nepi.resources.ns3.classes.node — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.node

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3node import NS3BaseNode 
    +
    +@clsinit_copy
    +
    [docs]class NS3Node(NS3BaseNode): + _rtype = "ns3::Node" + + @classmethod + def _register_attributes(cls): + + attr_id = Attribute("Id", + "The id (unique integer) of this Node.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_id) + + attr_systemid = Attribute("SystemId", + "The systemId of this node: a unique integer used for parallel simulations.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved) + + cls._register_attribute(attr_systemid) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3Node, self).__init__(ec, guid) + self._home = "ns3-node-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/non_communicating_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/non_communicating_net_device.html new file mode 100644 index 00000000..40302c41 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/non_communicating_net_device.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.non_communicating_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.non_communicating_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3NonCommunicatingNetDevice(NS3BaseNetDevice): + _rtype = "ns3::NonCommunicatingNetDevice" + + @classmethod + def _register_attributes(cls): + pass + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3NonCommunicatingNetDevice, self).__init__(ec, guid) + self._home = "ns3-non-communicating-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ocb_wifi_mac.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ocb_wifi_mac.html new file mode 100644 index 00000000..fe0ad5f4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ocb_wifi_mac.html @@ -0,0 +1,300 @@ + + + + + + + + nepi.resources.ns3.classes.ocb_wifi_mac — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.ocb_wifi_mac

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
    +
    +@clsinit_copy
    +
    [docs]class NS3OcbWifiMac(NS3BaseWifiMac): + _rtype = "ns3::OcbWifiMac" + + @classmethod + def _register_attributes(cls): + + attr_qossupported = Attribute("QosSupported", + "This Boolean attribute is set to enable 802.11e/WMM-style QoS support at this STA", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_qossupported) + + attr_htsupported = Attribute("HtSupported", + "This Boolean attribute is set to enable 802.11n support at this STA", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_htsupported) + + attr_ctstoselfsupported = Attribute("CtsToSelfSupported", + "Use CTS to Self when using a rate that is not in the basic set rate", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ctstoselfsupported) + + attr_ctstimeout = Attribute("CtsTimeout", + "When this timeout expires, the RTS/CTS handshake has failed.", + type = Types.String, + default = "+75000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ctstimeout) + + attr_acktimeout = Attribute("AckTimeout", + "When this timeout expires, the DATA/ACK handshake has failed.", + type = Types.String, + default = "+75000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_acktimeout) + + attr_basicblockacktimeout = Attribute("BasicBlockAckTimeout", + "When this timeout expires, the BASIC_BLOCK_ACK_REQ/BASIC_BLOCK_ACK handshake has failed.", + type = Types.String, + default = "+281000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_basicblockacktimeout) + + attr_compressedblockacktimeout = Attribute("CompressedBlockAckTimeout", + "When this timeout expires, the COMPRESSED_BLOCK_ACK_REQ/COMPRESSED_BLOCK_ACK handshake has failed.", + type = Types.String, + default = "+107000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_compressedblockacktimeout) + + attr_sifs = Attribute("Sifs", + "The value of the SIFS constant.", + type = Types.String, + default = "+16000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_sifs) + + attr_eifsnodifs = Attribute("EifsNoDifs", + "The value of EIFS-DIFS", + type = Types.String, + default = "+60000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_eifsnodifs) + + attr_slot = Attribute("Slot", + "The duration of a Slot.", + type = Types.String, + default = "+9000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_slot) + + attr_pifs = Attribute("Pifs", + "The value of the PIFS constant.", + type = Types.String, + default = "+25000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pifs) + + attr_rifs = Attribute("Rifs", + "The value of the RIFS constant.", + type = Types.String, + default = "+2000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rifs) + + attr_maxpropagationdelay = Attribute("MaxPropagationDelay", + "The maximum propagation delay. Unused for now.", + type = Types.String, + default = "+3333.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxpropagationdelay) + + attr_ssid = Attribute("Ssid", + "The ssid we want to belong to.", + type = Types.String, + default = "default", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ssid) + + + + @classmethod + def _register_traces(cls): + + txokheader = Trace("TxOkHeader", "The header of successfully transmitted packet") + + cls._register_trace(txokheader) + + txerrheader = Trace("TxErrHeader", "The header of unsuccessfully transmitted packet") + + cls._register_trace(txerrheader) + + mactx = Trace("MacTx", "A packet has been received from higher layers and is being processed in preparation for queueing for transmission.") + + cls._register_trace(mactx) + + mactxdrop = Trace("MacTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.") + + cls._register_trace(mactxdrop) + + macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(macpromiscrx) + + macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(macrx) + + macrxdrop = Trace("MacRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.") + + cls._register_trace(macrxdrop) + + + + def __init__(self, ec, guid): + super(NS3OcbWifiMac, self).__init__(ec, guid) + self._home = "ns3-ocb-wifi-mac-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/oh_buildings_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/oh_buildings_propagation_loss_model.html new file mode 100644 index 00000000..ceaa4abb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/oh_buildings_propagation_loss_model.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.classes.oh_buildings_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.oh_buildings_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3OhBuildingsPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::OhBuildingsPropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_shadowsigmaoutdoor = Attribute("ShadowSigmaOutdoor", + "Standard deviation of the normal distribution used for calculate the shadowing for outdoor nodes", + type = Types.Double, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_shadowsigmaoutdoor) + + attr_shadowsigmaindoor = Attribute("ShadowSigmaIndoor", + "Standard deviation of the normal distribution used for calculate the shadowing for indoor nodes ", + type = Types.Double, + default = "8", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_shadowsigmaindoor) + + attr_shadowsigmaextwalls = Attribute("ShadowSigmaExtWalls", + "Standard deviation of the normal distribution used for calculate the shadowing due to ext walls ", + type = Types.Double, + default = "5", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_shadowsigmaextwalls) + + attr_internalwallloss = Attribute("InternalWallLoss", + "Additional loss for each internal wall [dB]", + type = Types.Double, + default = "5", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_internalwallloss) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3OhBuildingsPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-oh-buildings-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/okumura_hata_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/okumura_hata_propagation_loss_model.html new file mode 100644 index 00000000..6426f914 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/okumura_hata_propagation_loss_model.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.okumura_hata_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.okumura_hata_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3OkumuraHataPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::OkumuraHataPropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_frequency = Attribute("Frequency", + "The propagation frequency in Hz", + type = Types.Double, + default = "2.16e+09", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_frequency) + + attr_environment = Attribute("Environment", + "Environment Scenario", + type = Types.Enumerate, + default = "Urban", + allowed = ["Urban","SubUrban","OpenAreas"], + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_environment) + + attr_citysize = Attribute("CitySize", + "Dimension of the city", + type = Types.Enumerate, + default = "Large", + allowed = ["Small","Medium","Large"], + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_citysize) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3OkumuraHataPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-okumura-hata-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/on_off_application.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/on_off_application.html new file mode 100644 index 00000000..d077a617 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/on_off_application.html @@ -0,0 +1,226 @@ + + + + + + + + nepi.resources.ns3.classes.on_off_application — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.on_off_application

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3application import NS3BaseApplication 
    +
    +@clsinit_copy
    +
    [docs]class NS3OnOffApplication(NS3BaseApplication): + _rtype = "ns3::OnOffApplication" + + @classmethod + def _register_attributes(cls): + + attr_datarate = Attribute("DataRate", + "The data rate in on state.", + type = Types.String, + default = "500000bps", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_datarate) + + attr_packetsize = Attribute("PacketSize", + "The size of packets sent in on state", + type = Types.Integer, + default = "512", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_packetsize) + + attr_remote = Attribute("Remote", + "The address of the destination", + type = Types.String, + default = "00-00-00", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_remote) + + attr_ontime = Attribute("OnTime", + "A RandomVariableStream used to pick the duration of the \'On\' state.", + type = Types.String, + default = "ns3::ConstantRandomVariable[Constant=1.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ontime) + + attr_offtime = Attribute("OffTime", + "A RandomVariableStream used to pick the duration of the \'Off\' state.", + type = Types.String, + default = "ns3::ConstantRandomVariable[Constant=1.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_offtime) + + attr_maxbytes = Attribute("MaxBytes", + "The total number of bytes to send. Once these bytes are sent, no packet is sent again, even in on state. The value zero means that there is no limit.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxbytes) + + attr_protocol = Attribute("Protocol", + "The type of protocol to use.", + type = Types.String, + default = "ns3::UdpSocketFactory", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_protocol) + + attr_starttime = Attribute("StartTime", + "Time at which the application will start", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_starttime) + + attr_stoptime = Attribute("StopTime", + "Time at which the application will stop", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stoptime) + + + + @classmethod + def _register_traces(cls): + + tx = Trace("Tx", "A new packet is created and is sent") + + cls._register_trace(tx) + + + + def __init__(self, ec, guid): + super(NS3OnOffApplication, self).__init__(ec, guid) + self._home = "ns3-on-off-application-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/onoe_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/onoe_wifi_manager.html new file mode 100644 index 00000000..5a657309 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/onoe_wifi_manager.html @@ -0,0 +1,248 @@ + + + + + + + + nepi.resources.ns3.classes.onoe_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.onoe_wifi_manager

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
    +
    +@clsinit_copy
    +
    [docs]class NS3OnoeWifiManager(NS3BaseWifiRemoteStationManager): + _rtype = "ns3::OnoeWifiManager" + + @classmethod + def _register_attributes(cls): + + attr_updateperiod = Attribute("UpdatePeriod", + "The interval between decisions about rate control changes", + type = Types.String, + default = "+1000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_updateperiod) + + attr_raisethreshold = Attribute("RaiseThreshold", + "Attempt to raise the rate if we hit that threshold", + type = Types.Integer, + default = "10", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_raisethreshold) + + attr_addcreditthreshold = Attribute("AddCreditThreshold", + "Add credit threshold", + type = Types.Integer, + default = "10", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_addcreditthreshold) + + attr_islowlatency = Attribute("IsLowLatency", + "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_islowlatency) + + attr_maxssrc = Attribute("MaxSsrc", + "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxssrc) + + attr_maxslrc = Attribute("MaxSlrc", + "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxslrc) + + attr_rtsctsthreshold = Attribute("RtsCtsThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2012, Section 9.3.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rtsctsthreshold) + + attr_fragmentationthreshold = Attribute("FragmentationThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2012, Section 9.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentationthreshold) + + attr_nonunicastmode = Attribute("NonUnicastMode", + "Wifi mode used for non-unicast transmissions.", + type = Types.String, + default = "Invalid-WifiMode", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_nonunicastmode) + + attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel", + "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaulttxpowerlevel) + + + + @classmethod + def _register_traces(cls): + + mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed") + + cls._register_trace(mactxrtsfailed) + + mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed") + + cls._register_trace(mactxdatafailed) + + mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinalrtsfailed) + + mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinaldatafailed) + + + + def __init__(self, ec, guid): + super(NS3OnoeWifiManager, self).__init__(ec, guid) + self._home = "ns3-onoe-wifi-manager-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/packet_sink.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/packet_sink.html new file mode 100644 index 00000000..06afb05a --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/packet_sink.html @@ -0,0 +1,176 @@ + + + + + + + + nepi.resources.ns3.classes.packet_sink — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.packet_sink

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3application import NS3BaseApplication 
    +
    +@clsinit_copy
    +
    [docs]class NS3PacketSink(NS3BaseApplication): + _rtype = "ns3::PacketSink" + + @classmethod + def _register_attributes(cls): + + attr_local = Attribute("Local", + "The Address on which to Bind the rx socket.", + type = Types.String, + default = "00-00-00", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_local) + + attr_protocol = Attribute("Protocol", + "The type id of the protocol to use for the rx socket.", + type = Types.String, + default = "ns3::UdpSocketFactory", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_protocol) + + attr_starttime = Attribute("StartTime", + "Time at which the application will start", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_starttime) + + attr_stoptime = Attribute("StopTime", + "Time at which the application will stop", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stoptime) + + + + @classmethod + def _register_traces(cls): + + rx = Trace("Rx", "A packet has been received") + + cls._register_trace(rx) + + + + def __init__(self, ec, guid): + super(NS3PacketSink, self).__init__(ec, guid) + self._home = "ns3-packet-sink-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ping6.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ping6.html new file mode 100644 index 00000000..7800ecfa --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ping6.html @@ -0,0 +1,201 @@ + + + + + + + + nepi.resources.ns3.classes.ping6 — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.ping6

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3application import NS3BaseApplication 
    +
    +@clsinit_copy
    +
    [docs]class NS3Ping6(NS3BaseApplication): + _rtype = "ns3::Ping6" + + @classmethod + def _register_attributes(cls): + + attr_maxpackets = Attribute("MaxPackets", + "The maximum number of packets the application will send", + type = Types.Integer, + default = "100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxpackets) + + attr_interval = Attribute("Interval", + "The time to wait between packets", + type = Types.String, + default = "+1000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_interval) + + attr_remoteipv6 = Attribute("RemoteIpv6", + "The Ipv6Address of the outbound packets", + type = Types.String, + default = "::", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_remoteipv6) + + attr_localipv6 = Attribute("LocalIpv6", + "Local Ipv6Address of the sender", + type = Types.String, + default = "::", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_localipv6) + + attr_packetsize = Attribute("PacketSize", + "Size of packets generated", + type = Types.Integer, + default = "100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_packetsize) + + attr_starttime = Attribute("StartTime", + "Time at which the application will start", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_starttime) + + attr_stoptime = Attribute("StopTime", + "Time at which the application will stop", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stoptime) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3Ping6, self).__init__(ec, guid) + self._home = "ns3-ping6-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_channel.html new file mode 100644 index 00000000..9633c160 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_channel.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.point_to_point_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.point_to_point_channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3channel import NS3BaseChannel 
    +
    +@clsinit_copy
    +
    [docs]class NS3PointToPointChannel(NS3BaseChannel): + _rtype = "ns3::PointToPointChannel" + + @classmethod + def _register_attributes(cls): + + attr_delay = Attribute("Delay", + "Transmission delay through the channel", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_delay) + + attr_id = Attribute("Id", + "The id (unique integer) of this Channel.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_id) + + + + @classmethod + def _register_traces(cls): + + txrxpointtopoint = Trace("TxRxPointToPoint", "Trace source indicating transmission of packet from the PointToPointChannel, used by the Animation interface.") + + cls._register_trace(txrxpointtopoint) + + + + def __init__(self, ec, guid): + super(NS3PointToPointChannel, self).__init__(ec, guid) + self._home = "ns3-point-to-point-channel-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_net_device.html new file mode 100644 index 00000000..b03bacfe --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_net_device.html @@ -0,0 +1,216 @@ + + + + + + + + nepi.resources.ns3.classes.point_to_point_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.point_to_point_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3PointToPointNetDevice(NS3BaseNetDevice): + _rtype = "ns3::PointToPointNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_mtu = Attribute("Mtu", + "The MAC-level Maximum Transmission Unit", + type = Types.Integer, + default = "1500", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + attr_address = Attribute("Address", + "The MAC address of this device.", + type = Types.String, + default = "ff:ff:ff:ff:ff:ff", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_address) + + attr_datarate = Attribute("DataRate", + "The default data rate for point to point links", + type = Types.String, + default = "32768bps", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_datarate) + + attr_interframegap = Attribute("InterframeGap", + "The time to wait between packet (frame) transmissions", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_interframegap) + + + + @classmethod + def _register_traces(cls): + + mactx = Trace("MacTx", "Trace source indicating a packet has arrived for transmission by this device") + + cls._register_trace(mactx) + + mactxdrop = Trace("MacTxDrop", "Trace source indicating a packet has been dropped by the device before transmission") + + cls._register_trace(mactxdrop) + + macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(macpromiscrx) + + macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(macrx) + + phytxbegin = Trace("PhyTxBegin", "Trace source indicating a packet has begun transmitting over the channel") + + cls._register_trace(phytxbegin) + + phytxend = Trace("PhyTxEnd", "Trace source indicating a packet has been completely transmitted over the channel") + + cls._register_trace(phytxend) + + phytxdrop = Trace("PhyTxDrop", "Trace source indicating a packet has been dropped by the device during transmission") + + cls._register_trace(phytxdrop) + + phyrxend = Trace("PhyRxEnd", "Trace source indicating a packet has been completely received by the device") + + cls._register_trace(phyrxend) + + phyrxdrop = Trace("PhyRxDrop", "Trace source indicating a packet has been dropped by the device during reception") + + cls._register_trace(phyrxdrop) + + sniffer = Trace("Sniffer", "Trace source simulating a non-promiscuous packet sniffer attached to the device") + + cls._register_trace(sniffer) + + promiscsniffer = Trace("PromiscSniffer", "Trace source simulating a promiscuous packet sniffer attached to the device") + + cls._register_trace(promiscsniffer) + + + + def __init__(self, ec, guid): + super(NS3PointToPointNetDevice, self).__init__(ec, guid) + self._home = "ns3-point-to-point-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_remote_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_remote_channel.html new file mode 100644 index 00000000..06166e88 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_remote_channel.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.point_to_point_remote_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.point_to_point_remote_channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3channel import NS3BaseChannel 
    +
    +@clsinit_copy
    +
    [docs]class NS3PointToPointRemoteChannel(NS3BaseChannel): + _rtype = "ns3::PointToPointRemoteChannel" + + @classmethod + def _register_attributes(cls): + + attr_delay = Attribute("Delay", + "Transmission delay through the channel", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_delay) + + attr_id = Attribute("Id", + "The id (unique integer) of this Channel.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_id) + + + + @classmethod + def _register_traces(cls): + + txrxpointtopoint = Trace("TxRxPointToPoint", "Trace source indicating transmission of packet from the PointToPointChannel, used by the Animation interface.") + + cls._register_trace(txrxpointtopoint) + + + + def __init__(self, ec, guid): + super(NS3PointToPointRemoteChannel, self).__init__(ec, guid) + self._home = "ns3-point-to-point-remote-channel-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/radvd.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/radvd.html new file mode 100644 index 00000000..0aa42df4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/radvd.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.radvd — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.radvd

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3application import NS3BaseApplication 
    +
    +@clsinit_copy
    +
    [docs]class NS3Radvd(NS3BaseApplication): + _rtype = "ns3::Radvd" + + @classmethod + def _register_attributes(cls): + + attr_advertisementjitter = Attribute("AdvertisementJitter", + "Uniform variable to provide jitter between min and max values of AdvInterval", + type = Types.String, + default = "ns3::UniformRandomVariable", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_advertisementjitter) + + attr_starttime = Attribute("StartTime", + "Time at which the application will start", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_starttime) + + attr_stoptime = Attribute("StopTime", + "Time at which the application will stop", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stoptime) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3Radvd, self).__init__(ec, guid) + self._home = "ns3-radvd-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_direction2d_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_direction2d_mobility_model.html new file mode 100644 index 00000000..22efa324 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_direction2d_mobility_model.html @@ -0,0 +1,186 @@ + + + + + + + + nepi.resources.ns3.classes.random_direction2d_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.random_direction2d_mobility_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3RandomDirection2dMobilityModel(NS3BaseMobilityModel): + _rtype = "ns3::RandomDirection2dMobilityModel" + + @classmethod + def _register_attributes(cls): + + attr_bounds = Attribute("Bounds", + "The 2d bounding area", + type = Types.String, + default = "-100|100|-100|100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_bounds) + + attr_speed = Attribute("Speed", + "A random variable to control the speed (m/s).", + type = Types.String, + default = "ns3::UniformRandomVariable[Min=1.0|Max=2.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_speed) + + attr_pause = Attribute("Pause", + "A random variable to control the pause (s).", + type = Types.String, + default = "ns3::ConstantRandomVariable[Constant=2.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pause) + + attr_position = Attribute("Position", + "The current position of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved) + + cls._register_attribute(attr_position) + + attr_velocity = Attribute("Velocity", + "The current velocity of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_velocity) + + + + @classmethod + def _register_traces(cls): + + coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed") + + cls._register_trace(coursechange) + + + + def __init__(self, ec, guid): + super(NS3RandomDirection2dMobilityModel, self).__init__(ec, guid) + self._home = "ns3-random-direction2d-mobility-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_delay_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_delay_model.html new file mode 100644 index 00000000..013f9fd8 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_delay_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.random_propagation_delay_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.random_propagation_delay_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationdelaymodel import NS3BasePropagationDelayModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3RandomPropagationDelayModel(NS3BasePropagationDelayModel): + _rtype = "ns3::RandomPropagationDelayModel" + + @classmethod + def _register_attributes(cls): + + attr_variable = Attribute("Variable", + "The random variable which generates random delays (s).", + type = Types.String, + default = "ns3::UniformRandomVariable", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_variable) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3RandomPropagationDelayModel, self).__init__(ec, guid) + self._home = "ns3-random-propagation-delay-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_loss_model.html new file mode 100644 index 00000000..67dfe0f8 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_loss_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.random_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.random_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3RandomPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::RandomPropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_variable = Attribute("Variable", + "The random variable used to pick a loss everytime CalcRxPower is invoked.", + type = Types.String, + default = "ns3::ConstantRandomVariable[Constant=1.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_variable) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3RandomPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-random-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_walk2d_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_walk2d_mobility_model.html new file mode 100644 index 00000000..2baf6a81 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_walk2d_mobility_model.html @@ -0,0 +1,216 @@ + + + + + + + + nepi.resources.ns3.classes.random_walk2d_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.random_walk2d_mobility_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3RandomWalk2dMobilityModel(NS3BaseMobilityModel): + _rtype = "ns3::RandomWalk2dMobilityModel" + + @classmethod + def _register_attributes(cls): + + attr_bounds = Attribute("Bounds", + "Bounds of the area to cruise.", + type = Types.String, + default = "0|100|0|100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_bounds) + + attr_time = Attribute("Time", + "Change current direction and speed after moving for this delay.", + type = Types.String, + default = "+1000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_time) + + attr_distance = Attribute("Distance", + "Change current direction and speed after moving for this distance.", + type = Types.Double, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_distance) + + attr_mode = Attribute("Mode", + "The mode indicates the condition used to change the current speed and direction", + type = Types.Enumerate, + default = "Distance", + allowed = ["Distance","Time"], + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mode) + + attr_direction = Attribute("Direction", + "A random variable used to pick the direction (gradients).", + type = Types.String, + default = "ns3::UniformRandomVariable[Min=0.0|Max=6.283184]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_direction) + + attr_speed = Attribute("Speed", + "A random variable used to pick the speed (m/s).", + type = Types.String, + default = "ns3::UniformRandomVariable[Min=2.0|Max=4.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_speed) + + attr_position = Attribute("Position", + "The current position of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved) + + cls._register_attribute(attr_position) + + attr_velocity = Attribute("Velocity", + "The current velocity of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_velocity) + + + + @classmethod + def _register_traces(cls): + + coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed") + + cls._register_trace(coursechange) + + + + def __init__(self, ec, guid): + super(NS3RandomWalk2dMobilityModel, self).__init__(ec, guid) + self._home = "ns3-random-walk2d-mobility-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_waypoint_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_waypoint_mobility_model.html new file mode 100644 index 00000000..c2549aeb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_waypoint_mobility_model.html @@ -0,0 +1,176 @@ + + + + + + + + nepi.resources.ns3.classes.random_waypoint_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.random_waypoint_mobility_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3RandomWaypointMobilityModel(NS3BaseMobilityModel): + _rtype = "ns3::RandomWaypointMobilityModel" + + @classmethod + def _register_attributes(cls): + + attr_speed = Attribute("Speed", + "A random variable used to pick the speed of a random waypoint model.", + type = Types.String, + default = "ns3::UniformRandomVariable[Min=0.3|Max=0.7]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_speed) + + attr_pause = Attribute("Pause", + "A random variable used to pick the pause of a random waypoint model.", + type = Types.String, + default = "ns3::ConstantRandomVariable[Constant=2.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pause) + + attr_position = Attribute("Position", + "The current position of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved) + + cls._register_attribute(attr_position) + + attr_velocity = Attribute("Velocity", + "The current velocity of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_velocity) + + + + @classmethod + def _register_traces(cls): + + coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed") + + cls._register_trace(coursechange) + + + + def __init__(self, ec, guid): + super(NS3RandomWaypointMobilityModel, self).__init__(ec, guid) + self._home = "ns3-random-waypoint-mobility-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/range_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/range_propagation_loss_model.html new file mode 100644 index 00000000..12a038c1 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/range_propagation_loss_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.range_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.range_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3RangePropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::RangePropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_maxrange = Attribute("MaxRange", + "Maximum Transmission Range (meters)", + type = Types.Double, + default = "250", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxrange) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3RangePropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-range-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rate_error_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rate_error_model.html new file mode 100644 index 00000000..df1f4f9f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rate_error_model.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.classes.rate_error_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.rate_error_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3RateErrorModel(NS3BaseErrorModel): + _rtype = "ns3::RateErrorModel" + + @classmethod + def _register_attributes(cls): + + attr_errorunit = Attribute("ErrorUnit", + "The error unit", + type = Types.Enumerate, + default = "ERROR_UNIT_BYTE", + allowed = ["ERROR_UNIT_BIT","ERROR_UNIT_BYTE","ERROR_UNIT_PACKET"], + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_errorunit) + + attr_errorrate = Attribute("ErrorRate", + "The error rate.", + type = Types.Double, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_errorrate) + + attr_ranvar = Attribute("RanVar", + "The decision variable attached to this error model.", + type = Types.String, + default = "ns3::UniformRandomVariable[Min=0.0|Max=1.0]", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ranvar) + + attr_isenabled = Attribute("IsEnabled", + "Whether this ErrorModel is enabled or not.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_isenabled) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3RateErrorModel, self).__init__(ec, guid) + self._home = "ns3-rate-error-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/receive_list_error_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/receive_list_error_model.html new file mode 100644 index 00000000..dcf10c00 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/receive_list_error_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.receive_list_error_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.receive_list_error_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3ReceiveListErrorModel(NS3BaseErrorModel): + _rtype = "ns3::ReceiveListErrorModel" + + @classmethod + def _register_attributes(cls): + + attr_isenabled = Attribute("IsEnabled", + "Whether this ErrorModel is enabled or not.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_isenabled) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3ReceiveListErrorModel, self).__init__(ec, guid) + self._home = "ns3-receive-list-error-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/red_queue.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/red_queue.html new file mode 100644 index 00000000..1a49a0f9 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/red_queue.html @@ -0,0 +1,264 @@ + + + + + + + + nepi.resources.ns3.classes.red_queue — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.red_queue

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3queue import NS3BaseQueue 
    +
    +@clsinit_copy
    +
    [docs]class NS3RedQueue(NS3BaseQueue): + _rtype = "ns3::RedQueue" + + @classmethod + def _register_attributes(cls): + + attr_meanpktsize = Attribute("MeanPktSize", + "Average of packet size", + type = Types.Integer, + default = "500", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_meanpktsize) + + attr_idlepktsize = Attribute("IdlePktSize", + "Average packet size used during idle times. Used when m_cautions = 3", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_idlepktsize) + + attr_wait = Attribute("Wait", + "True for waiting between dropped packets", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_wait) + + attr_gentle = Attribute("Gentle", + "True to increases dropping probability slowly when average queue exceeds maxthresh", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_gentle) + + attr_minth = Attribute("MinTh", + "Minimum average length threshold in packets/bytes", + type = Types.Double, + default = "5", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_minth) + + attr_maxth = Attribute("MaxTh", + "Maximum average length threshold in packets/bytes", + type = Types.Double, + default = "15", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxth) + + attr_queuelimit = Attribute("QueueLimit", + "Queue limit in bytes/packets", + type = Types.Integer, + default = "25", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_queuelimit) + + attr_qw = Attribute("QW", + "Queue weight related to the exponential weighted moving average (EWMA)", + type = Types.Double, + default = "0.002", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_qw) + + attr_linterm = Attribute("LInterm", + "The maximum probability of dropping a packet", + type = Types.Double, + default = "50", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_linterm) + + attr_ns1compat = Attribute("Ns1Compat", + "NS-1 compatibility", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ns1compat) + + attr_linkbandwidth = Attribute("LinkBandwidth", + "The RED link bandwidth", + type = Types.String, + default = "1500000bps", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_linkbandwidth) + + attr_linkdelay = Attribute("LinkDelay", + "The RED link delay", + type = Types.String, + default = "+20000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_linkdelay) + + + + @classmethod + def _register_traces(cls): + + enqueue = Trace("Enqueue", "Enqueue a packet in the queue.") + + cls._register_trace(enqueue) + + dequeue = Trace("Dequeue", "Dequeue a packet from the queue.") + + cls._register_trace(dequeue) + + drop = Trace("Drop", "Drop a packet stored in the queue.") + + cls._register_trace(drop) + + + + def __init__(self, ec, guid): + super(NS3RedQueue, self).__init__(ec, guid) + self._home = "ns3-red-queue-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rraa_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rraa_wifi_manager.html new file mode 100644 index 00000000..68fa6daf --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rraa_wifi_manager.html @@ -0,0 +1,458 @@ + + + + + + + + nepi.resources.ns3.classes.rraa_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.rraa_wifi_manager

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
    +
    +@clsinit_copy
    +
    [docs]class NS3RraaWifiManager(NS3BaseWifiRemoteStationManager): + _rtype = "ns3::RraaWifiManager" + + @classmethod + def _register_attributes(cls): + + attr_basic = Attribute("Basic", + "If true the RRAA-BASIC algorithm will be used, otherwise the RRAA wil be used", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_basic) + + attr_timeout = Attribute("Timeout", + "Timeout for the RRAA BASIC loss estimaton block (s)", + type = Types.String, + default = "+50000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_timeout) + + attr_ewndfor54mbps = Attribute("ewndFor54mbps", + "ewnd parameter for 54 Mbs data mode", + type = Types.Integer, + default = "40", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ewndfor54mbps) + + attr_ewndfor48mbps = Attribute("ewndFor48mbps", + "ewnd parameter for 48 Mbs data mode", + type = Types.Integer, + default = "40", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ewndfor48mbps) + + attr_ewndfor36mbps = Attribute("ewndFor36mbps", + "ewnd parameter for 36 Mbs data mode", + type = Types.Integer, + default = "40", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ewndfor36mbps) + + attr_ewndfor24mbps = Attribute("ewndFor24mbps", + "ewnd parameter for 24 Mbs data mode", + type = Types.Integer, + default = "40", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ewndfor24mbps) + + attr_ewndfor18mbps = Attribute("ewndFor18mbps", + "ewnd parameter for 18 Mbs data mode", + type = Types.Integer, + default = "20", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ewndfor18mbps) + + attr_ewndfor12mbps = Attribute("ewndFor12mbps", + "ewnd parameter for 12 Mbs data mode", + type = Types.Integer, + default = "20", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ewndfor12mbps) + + attr_ewndfor9mbps = Attribute("ewndFor9mbps", + "ewnd parameter for 9 Mbs data mode", + type = Types.Integer, + default = "10", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ewndfor9mbps) + + attr_ewndfor6mbps = Attribute("ewndFor6mbps", + "ewnd parameter for 6 Mbs data mode", + type = Types.Integer, + default = "6", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ewndfor6mbps) + + attr_porifor48mbps = Attribute("poriFor48mbps", + "Pori parameter for 48 Mbs data mode", + type = Types.Double, + default = "0.047", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_porifor48mbps) + + attr_porifor36mbps = Attribute("poriFor36mbps", + "Pori parameter for 36 Mbs data mode", + type = Types.Double, + default = "0.115", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_porifor36mbps) + + attr_porifor24mbps = Attribute("poriFor24mbps", + "Pori parameter for 24 Mbs data mode", + type = Types.Double, + default = "0.1681", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_porifor24mbps) + + attr_porifor18mbps = Attribute("poriFor18mbps", + "Pori parameter for 18 Mbs data mode", + type = Types.Double, + default = "0.1325", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_porifor18mbps) + + attr_porifor12mbps = Attribute("poriFor12mbps", + "Pori parameter for 12 Mbs data mode", + type = Types.Double, + default = "0.1861", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_porifor12mbps) + + attr_porifor9mbps = Attribute("poriFor9mbps", + "Pori parameter for 9 Mbs data mode", + type = Types.Double, + default = "0.1434", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_porifor9mbps) + + attr_porifor6mbps = Attribute("poriFor6mbps", + "Pori parameter for 6 Mbs data mode", + type = Types.Double, + default = "0.5", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_porifor6mbps) + + attr_pmtlfor54mbps = Attribute("pmtlFor54mbps", + "Pmtl parameter for 54 Mbs data mode", + type = Types.Double, + default = "0.094", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pmtlfor54mbps) + + attr_pmtlfor48mbps = Attribute("pmtlFor48mbps", + "Pmtl parameter for 48 Mbs data mode", + type = Types.Double, + default = "0.23", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pmtlfor48mbps) + + attr_pmtlfor36mbps = Attribute("pmtlFor36mbps", + "Pmtl parameter for 36 Mbs data mode", + type = Types.Double, + default = "0.3363", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pmtlfor36mbps) + + attr_pmtlfor24mbps = Attribute("pmtlFor24mbps", + "Pmtl parameter for 24 Mbs data mode", + type = Types.Double, + default = "0.265", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pmtlfor24mbps) + + attr_pmtlfor18mbps = Attribute("pmtlFor18mbps", + "Pmtl parameter for 18 Mbs data mode", + type = Types.Double, + default = "0.3722", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pmtlfor18mbps) + + attr_pmtlfor12mbps = Attribute("pmtlFor12mbps", + "Pmtl parameter for 12 Mbs data mode", + type = Types.Double, + default = "0.2868", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pmtlfor12mbps) + + attr_pmtlfor9mbps = Attribute("pmtlFor9mbps", + "Pmtl parameter for 9 Mbs data mode", + type = Types.Double, + default = "0.3932", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pmtlfor9mbps) + + attr_islowlatency = Attribute("IsLowLatency", + "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_islowlatency) + + attr_maxssrc = Attribute("MaxSsrc", + "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxssrc) + + attr_maxslrc = Attribute("MaxSlrc", + "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxslrc) + + attr_rtsctsthreshold = Attribute("RtsCtsThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2012, Section 9.3.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rtsctsthreshold) + + attr_fragmentationthreshold = Attribute("FragmentationThreshold", + "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2012, Section 9.5. This value will not have any effect on some rate control algorithms.", + type = Types.Integer, + default = "2346", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentationthreshold) + + attr_nonunicastmode = Attribute("NonUnicastMode", + "Wifi mode used for non-unicast transmissions.", + type = Types.String, + default = "Invalid-WifiMode", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_nonunicastmode) + + attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel", + "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_defaulttxpowerlevel) + + + + @classmethod + def _register_traces(cls): + + mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed") + + cls._register_trace(mactxrtsfailed) + + mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed") + + cls._register_trace(mactxdatafailed) + + mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinalrtsfailed) + + mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts") + + cls._register_trace(mactxfinaldatafailed) + + + + def __init__(self, ec, guid): + super(NS3RraaWifiManager, self).__init__(ec, guid) + self._home = "ns3-rraa-wifi-manager-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_channel.html new file mode 100644 index 00000000..afa2fd81 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_channel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.simple_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.simple_channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3channel import NS3BaseChannel 
    +
    +@clsinit_copy
    +
    [docs]class NS3SimpleChannel(NS3BaseChannel): + _rtype = "ns3::SimpleChannel" + + @classmethod + def _register_attributes(cls): + + attr_id = Attribute("Id", + "The id (unique integer) of this Channel.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_id) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3SimpleChannel, self).__init__(ec, guid) + self._home = "ns3-simple-channel-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_net_device.html new file mode 100644 index 00000000..da4586bb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_net_device.html @@ -0,0 +1,135 @@ + + + + + + + + nepi.resources.ns3.classes.simple_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.simple_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3SimpleNetDevice(NS3BaseNetDevice): + _rtype = "ns3::SimpleNetDevice" + + @classmethod + def _register_attributes(cls): + pass + + @classmethod + def _register_traces(cls): + + phyrxdrop = Trace("PhyRxDrop", "Trace source indicating a packet has been dropped by the device during reception") + + cls._register_trace(phyrxdrop) + + + + def __init__(self, ec, guid): + super(NS3SimpleNetDevice, self).__init__(ec, guid) + self._home = "ns3-simple-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/single_model_spectrum_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/single_model_spectrum_channel.html new file mode 100644 index 00000000..7570e780 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/single_model_spectrum_channel.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.single_model_spectrum_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.single_model_spectrum_channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3channel import NS3BaseChannel 
    +
    +@clsinit_copy
    +
    [docs]class NS3SingleModelSpectrumChannel(NS3BaseChannel): + _rtype = "ns3::SingleModelSpectrumChannel" + + @classmethod + def _register_attributes(cls): + + attr_maxlossdb = Attribute("MaxLossDb", + "If a single-frequency PropagationLossModel is used, this value represents the maximum loss in dB for which transmissions will be passed to the receiving PHY. Signals for which the PropagationLossModel returns a loss bigger than this value will not be propagated to the receiver. This parameter is to be used to reduce the computational load by not propagating signals that are far beyond the interference range. Note that the default value corresponds to considering all signals for reception. Tune this value with care. ", + type = Types.Double, + default = "1e+09", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxlossdb) + + attr_id = Attribute("Id", + "The id (unique integer) of this Channel.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_id) + + + + @classmethod + def _register_traces(cls): + + pathloss = Trace("PathLoss", "This trace is fired whenever a new path loss value is calculated. The first and second parameters to the trace are pointers respectively to the TX and RX SpectrumPhy instances, whereas the third parameters is the loss value in dB. Note that the loss value reported by this trace is the single-frequency loss value obtained by evaluating only the TX and RX AntennaModels and the PropagationLossModel. In particular, note that SpectrumPropagationLossModel (even if present) is never used to evaluate the loss value reported in this trace. ") + + cls._register_trace(pathloss) + + + + def __init__(self, ec, guid): + super(NS3SingleModelSpectrumChannel, self).__init__(ec, guid) + self._home = "ns3-single-model-spectrum-channel-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/six_low_pan_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/six_low_pan_net_device.html new file mode 100644 index 00000000..d4be2bb4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/six_low_pan_net_device.html @@ -0,0 +1,214 @@ + + + + + + + + nepi.resources.ns3.classes.six_low_pan_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.six_low_pan_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3SixLowPanNetDevice(NS3BaseNetDevice): + _rtype = "ns3::SixLowPanNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_rfc6282 = Attribute("Rfc6282", + "Use RFC6282 (IPHC) if true, RFC4944 (HC1) otherwise.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rfc6282) + + attr_omitudpchecksum = Attribute("OmitUdpChecksum", + "Omit the UDP checksum in IPHC compression.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_omitudpchecksum) + + attr_fragmentreassemblylistsize = Attribute("FragmentReassemblyListSize", + "The maximum size of the reassembly buffer (in packets). Zero meaning infinite.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentreassemblylistsize) + + attr_fragmentexpirationtimeout = Attribute("FragmentExpirationTimeout", + "When this timeout expires, the fragments will be cleared from the buffer.", + type = Types.String, + default = "+60000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentexpirationtimeout) + + attr_compressionthreshold = Attribute("CompressionThreshold", + "The minimum MAC layer payload size.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_compressionthreshold) + + attr_forceethertype = Attribute("ForceEtherType", + "Force a specific EtherType in L2 frames.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_forceethertype) + + attr_ethertype = Attribute("EtherType", + "The specific EtherType to be used in L2 frames.", + type = Types.Integer, + default = "65535", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ethertype) + + + + @classmethod + def _register_traces(cls): + + tx = Trace("Tx", "Send - packet (including 6LoWPAN header), SixLoWPanNetDevice Ptr, interface index.") + + cls._register_trace(tx) + + rx = Trace("Rx", "Receive - packet (including 6LoWPAN header), SixLoWPanNetDevice Ptr, interface index.") + + cls._register_trace(rx) + + drop = Trace("Drop", "Drop - DropReason, packet (including 6LoWPAN header), SixLoWPanNetDevice Ptr, interface index.") + + cls._register_trace(drop) + + + + def __init__(self, ec, guid): + super(NS3SixLowPanNetDevice, self).__init__(ec, guid) + self._home = "ns3-six-low-pan-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/sta_wifi_mac.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/sta_wifi_mac.html new file mode 100644 index 00000000..d695e43f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/sta_wifi_mac.html @@ -0,0 +1,348 @@ + + + + + + + + nepi.resources.ns3.classes.sta_wifi_mac — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.sta_wifi_mac

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
    +
    +@clsinit_copy
    +
    [docs]class NS3StaWifiMac(NS3BaseWifiMac): + _rtype = "ns3::StaWifiMac" + + @classmethod + def _register_attributes(cls): + + attr_proberequesttimeout = Attribute("ProbeRequestTimeout", + "The interval between two consecutive probe request attempts.", + type = Types.String, + default = "+50000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_proberequesttimeout) + + attr_assocrequesttimeout = Attribute("AssocRequestTimeout", + "The interval between two consecutive assoc request attempts.", + type = Types.String, + default = "+500000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_assocrequesttimeout) + + attr_maxmissedbeacons = Attribute("MaxMissedBeacons", + "Number of beacons which much be consecutively missed before we attempt to restart association.", + type = Types.Integer, + default = "10", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxmissedbeacons) + + attr_activeprobing = Attribute("ActiveProbing", + "If true, we send probe requests. If false, we don\'t. NOTE: if more than one STA in your simulation is using active probing, you should enable it at a different simulation time for each STA, otherwise all the STAs will start sending probes at the same time resulting in collisions. See bug 1060 for more info.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_activeprobing) + + attr_qossupported = Attribute("QosSupported", + "This Boolean attribute is set to enable 802.11e/WMM-style QoS support at this STA", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_qossupported) + + attr_htsupported = Attribute("HtSupported", + "This Boolean attribute is set to enable 802.11n support at this STA", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_htsupported) + + attr_ctstoselfsupported = Attribute("CtsToSelfSupported", + "Use CTS to Self when using a rate that is not in the basic set rate", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ctstoselfsupported) + + attr_ctstimeout = Attribute("CtsTimeout", + "When this timeout expires, the RTS/CTS handshake has failed.", + type = Types.String, + default = "+75000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ctstimeout) + + attr_acktimeout = Attribute("AckTimeout", + "When this timeout expires, the DATA/ACK handshake has failed.", + type = Types.String, + default = "+75000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_acktimeout) + + attr_basicblockacktimeout = Attribute("BasicBlockAckTimeout", + "When this timeout expires, the BASIC_BLOCK_ACK_REQ/BASIC_BLOCK_ACK handshake has failed.", + type = Types.String, + default = "+281000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_basicblockacktimeout) + + attr_compressedblockacktimeout = Attribute("CompressedBlockAckTimeout", + "When this timeout expires, the COMPRESSED_BLOCK_ACK_REQ/COMPRESSED_BLOCK_ACK handshake has failed.", + type = Types.String, + default = "+107000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_compressedblockacktimeout) + + attr_sifs = Attribute("Sifs", + "The value of the SIFS constant.", + type = Types.String, + default = "+16000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_sifs) + + attr_eifsnodifs = Attribute("EifsNoDifs", + "The value of EIFS-DIFS", + type = Types.String, + default = "+60000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_eifsnodifs) + + attr_slot = Attribute("Slot", + "The duration of a Slot.", + type = Types.String, + default = "+9000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_slot) + + attr_pifs = Attribute("Pifs", + "The value of the PIFS constant.", + type = Types.String, + default = "+25000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_pifs) + + attr_rifs = Attribute("Rifs", + "The value of the RIFS constant.", + type = Types.String, + default = "+2000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rifs) + + attr_maxpropagationdelay = Attribute("MaxPropagationDelay", + "The maximum propagation delay. Unused for now.", + type = Types.String, + default = "+3333.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxpropagationdelay) + + attr_ssid = Attribute("Ssid", + "The ssid we want to belong to.", + type = Types.String, + default = "default", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ssid) + + + + @classmethod + def _register_traces(cls): + + assoc = Trace("Assoc", "Associated with an access point.") + + cls._register_trace(assoc) + + deassoc = Trace("DeAssoc", "Association with an access point lost.") + + cls._register_trace(deassoc) + + txokheader = Trace("TxOkHeader", "The header of successfully transmitted packet") + + cls._register_trace(txokheader) + + txerrheader = Trace("TxErrHeader", "The header of unsuccessfully transmitted packet") + + cls._register_trace(txerrheader) + + mactx = Trace("MacTx", "A packet has been received from higher layers and is being processed in preparation for queueing for transmission.") + + cls._register_trace(mactx) + + mactxdrop = Trace("MacTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.") + + cls._register_trace(mactxdrop) + + macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(macpromiscrx) + + macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(macrx) + + macrxdrop = Trace("MacRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.") + + cls._register_trace(macrxdrop) + + + + def __init__(self, ec, guid): + super(NS3StaWifiMac, self).__init__(ec, guid) + self._home = "ns3-sta-wifi-mac-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/steady_state_random_waypoint_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/steady_state_random_waypoint_mobility_model.html new file mode 100644 index 00000000..03aaaedc --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/steady_state_random_waypoint_mobility_model.html @@ -0,0 +1,246 @@ + + + + + + + + nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3SteadyStateRandomWaypointMobilityModel(NS3BaseMobilityModel): + _rtype = "ns3::SteadyStateRandomWaypointMobilityModel" + + @classmethod + def _register_attributes(cls): + + attr_minspeed = Attribute("MinSpeed", + "Minimum speed value, [m/s]", + type = Types.Double, + default = "0.3", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_minspeed) + + attr_maxspeed = Attribute("MaxSpeed", + "Maximum speed value, [m/s]", + type = Types.Double, + default = "0.7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxspeed) + + attr_minpause = Attribute("MinPause", + "Minimum pause value, [s]", + type = Types.Double, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_minpause) + + attr_maxpause = Attribute("MaxPause", + "Maximum pause value, [s]", + type = Types.Double, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxpause) + + attr_minx = Attribute("MinX", + "Minimum X value of traveling region, [m]", + type = Types.Double, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_minx) + + attr_maxx = Attribute("MaxX", + "Maximum X value of traveling region, [m]", + type = Types.Double, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxx) + + attr_miny = Attribute("MinY", + "Minimum Y value of traveling region, [m]", + type = Types.Double, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_miny) + + attr_maxy = Attribute("MaxY", + "Maximum Y value of traveling region, [m]", + type = Types.Double, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxy) + + attr_z = Attribute("Z", + "Z value of traveling region (fixed), [m]", + type = Types.Double, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_z) + + attr_position = Attribute("Position", + "The current position of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved) + + cls._register_attribute(attr_position) + + attr_velocity = Attribute("Velocity", + "The current velocity of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_velocity) + + + + @classmethod + def _register_traces(cls): + + coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed") + + cls._register_trace(coursechange) + + + + def __init__(self, ec, guid): + super(NS3SteadyStateRandomWaypointMobilityModel, self).__init__(ec, guid) + self._home = "ns3-steady-state-random-waypoint-mobility-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/subscriber_station_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/subscriber_station_net_device.html new file mode 100644 index 00000000..45bace14 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/subscriber_station_net_device.html @@ -0,0 +1,306 @@ + + + + + + + + nepi.resources.ns3.classes.subscriber_station_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.subscriber_station_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3SubscriberStationNetDevice(NS3BaseNetDevice): + _rtype = "ns3::SubscriberStationNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_lostdlmapinterval = Attribute("LostDlMapInterval", + "Time since last received DL-MAP message before downlink synchronization is considered lost. Maximum is 600ms", + type = Types.String, + default = "+500000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_lostdlmapinterval) + + attr_lostulmapinterval = Attribute("LostUlMapInterval", + "Time since last received UL-MAP before uplink synchronization is considered lost, maximum is 600.", + type = Types.String, + default = "+500000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_lostulmapinterval) + + attr_maxdcdinterval = Attribute("MaxDcdInterval", + "Maximum time between transmission of DCD messages. Maximum is 10s", + type = Types.String, + default = "+10000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxdcdinterval) + + attr_maxucdinterval = Attribute("MaxUcdInterval", + "Maximum time between transmission of UCD messages. Maximum is 10s", + type = Types.String, + default = "+10000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxucdinterval) + + attr_intervalt1 = Attribute("IntervalT1", + "Wait for DCD timeout. Maximum is 5*maxDcdInterval", + type = Types.String, + default = "+50000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_intervalt1) + + attr_intervalt2 = Attribute("IntervalT2", + "Wait for broadcast ranging timeout, i.e., wait for initial ranging opportunity. Maximum is 5*Ranging interval", + type = Types.String, + default = "+10000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_intervalt2) + + attr_intervalt3 = Attribute("IntervalT3", + "ranging Response reception timeout following the transmission of a ranging request. Maximum is 200ms", + type = Types.String, + default = "+200000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_intervalt3) + + attr_intervalt7 = Attribute("IntervalT7", + "wait for DSA/DSC/DSD Response timeout. Maximum is 1s", + type = Types.String, + default = "+100000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_intervalt7) + + attr_intervalt12 = Attribute("IntervalT12", + "Wait for UCD descriptor.Maximum is 5*MaxUcdInterval", + type = Types.String, + default = "+10000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_intervalt12) + + attr_intervalt20 = Attribute("IntervalT20", + "Time the SS searches for preambles on a given channel. Minimum is 2 MAC frames", + type = Types.String, + default = "+500000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_intervalt20) + + attr_intervalt21 = Attribute("IntervalT21", + "time the SS searches for (decodable) DL-MAP on a given channel", + type = Types.String, + default = "+10000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_intervalt21) + + attr_maxcontentionrangingretries = Attribute("MaxContentionRangingRetries", + "Number of retries on contention Ranging Requests", + type = Types.Integer, + default = "16", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxcontentionrangingretries) + + attr_mtu = Attribute("Mtu", + "The MAC-level Maximum Transmission Unit", + type = Types.Integer, + default = "1400", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + attr_rtg = Attribute("RTG", + "receive/transmit transition gap.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rtg) + + attr_ttg = Attribute("TTG", + "transmit/receive transition gap.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ttg) + + + + @classmethod + def _register_traces(cls): + + sstxdrop = Trace("SSTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.") + + cls._register_trace(sstxdrop) + + sspromiscrx = Trace("SSPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(sspromiscrx) + + ssrx = Trace("SSRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(ssrx) + + ssrxdrop = Trace("SSRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.") + + cls._register_trace(ssrxdrop) + + rx = Trace("Rx", "Receive trace") + + cls._register_trace(rx) + + tx = Trace("Tx", "Transmit trace") + + cls._register_trace(tx) + + + + def __init__(self, ec, guid): + super(NS3SubscriberStationNetDevice, self).__init__(ec, guid) + self._home = "ns3-subscriber-station-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tap_bridge.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tap_bridge.html new file mode 100644 index 00000000..0f26c6be --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tap_bridge.html @@ -0,0 +1,211 @@ + + + + + + + + nepi.resources.ns3.classes.tap_bridge — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.tap_bridge

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3TapBridge(NS3BaseNetDevice): + _rtype = "ns3::TapBridge" + + @classmethod + def _register_attributes(cls): + + attr_mtu = Attribute("Mtu", + "The MAC-level Maximum Transmission Unit", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + attr_devicename = Attribute("DeviceName", + "The name of the tap device to create.", + type = Types.String, + default = "", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_devicename) + + attr_gateway = Attribute("Gateway", + "The IP address of the default gateway to assign to the host machine, when in ConfigureLocal mode.", + type = Types.String, + default = "255.255.255.255", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_gateway) + + attr_ipaddress = Attribute("IpAddress", + "The IP address to assign to the tap device, when in ConfigureLocal mode. This address will override the discovered IP address of the simulated device.", + type = Types.String, + default = "255.255.255.255", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ipaddress) + + attr_macaddress = Attribute("MacAddress", + "The MAC address to assign to the tap device, when in ConfigureLocal mode. This address will override the discovered MAC address of the simulated device.", + type = Types.String, + default = "ff:ff:ff:ff:ff:ff", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_macaddress) + + attr_netmask = Attribute("Netmask", + "The network mask to assign to the tap device, when in ConfigureLocal mode. This address will override the discovered MAC address of the simulated device.", + type = Types.String, + default = "255.255.255.255", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_netmask) + + attr_start = Attribute("Start", + "The simulation time at which to spin up the tap device read thread.", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_start) + + attr_stop = Attribute("Stop", + "The simulation time at which to tear down the tap device read thread.", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stop) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3TapBridge, self).__init__(ec, guid) + self._home = "ns3-tap-bridge-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tcp_l4protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tcp_l4protocol.html new file mode 100644 index 00000000..27e51dbd --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tcp_l4protocol.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.tcp_l4protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.tcp_l4protocol

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3TcpL4Protocol(NS3Base): + _rtype = "ns3::TcpL4Protocol" + + @classmethod + def _register_attributes(cls): + + attr_rttestimatortype = Attribute("RttEstimatorType", + "Type of RttEstimator objects.", + type = Types.String, + default = "ns3::RttMeanDeviation", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rttestimatortype) + + attr_sockettype = Attribute("SocketType", + "Socket type of TCP objects.", + type = Types.String, + default = "ns3::TcpNewReno", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_sockettype) + + attr_protocolnumber = Attribute("ProtocolNumber", + "The Ip protocol number.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_protocolnumber) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3TcpL4Protocol, self).__init__(ec, guid) + self._home = "ns3-tcp-l4protocol-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/three_log_distance_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/three_log_distance_propagation_loss_model.html new file mode 100644 index 00000000..458f0bbe --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/three_log_distance_propagation_loss_model.html @@ -0,0 +1,201 @@ + + + + + + + + nepi.resources.ns3.classes.three_log_distance_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.three_log_distance_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3ThreeLogDistancePropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::ThreeLogDistancePropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_distance0 = Attribute("Distance0", + "Beginning of the first (near) distance field", + type = Types.Double, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_distance0) + + attr_distance1 = Attribute("Distance1", + "Beginning of the second (middle) distance field.", + type = Types.Double, + default = "200", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_distance1) + + attr_distance2 = Attribute("Distance2", + "Beginning of the third (far) distance field.", + type = Types.Double, + default = "500", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_distance2) + + attr_exponent0 = Attribute("Exponent0", + "The exponent for the first field.", + type = Types.Double, + default = "1.9", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_exponent0) + + attr_exponent1 = Attribute("Exponent1", + "The exponent for the second field.", + type = Types.Double, + default = "3.8", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_exponent1) + + attr_exponent2 = Attribute("Exponent2", + "The exponent for the third field.", + type = Types.Double, + default = "3.8", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_exponent2) + + attr_referenceloss = Attribute("ReferenceLoss", + "The reference loss at distance d0 (dB). (Default is Friis at 1m with 5.15 GHz)", + type = Types.Double, + default = "46.6777", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_referenceloss) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3ThreeLogDistancePropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-three-log-distance-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/two_ray_ground_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/two_ray_ground_propagation_loss_model.html new file mode 100644 index 00000000..3a34d749 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/two_ray_ground_propagation_loss_model.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3TwoRayGroundPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::TwoRayGroundPropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_frequency = Attribute("Frequency", + "The carrier frequency (in Hz) at which propagation occurs (default is 5.15 GHz).", + type = Types.Double, + default = "5.15e+09", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_frequency) + + attr_systemloss = Attribute("SystemLoss", + "The system loss", + type = Types.Double, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_systemloss) + + attr_mindistance = Attribute("MinDistance", + "The distance under which the propagation model refuses to give results (m)", + type = Types.Double, + default = "0.5", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mindistance) + + attr_heightabovez = Attribute("HeightAboveZ", + "The height of the antenna (m) above the node\'s Z coordinate", + type = Types.Double, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_heightabovez) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3TwoRayGroundPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-two-ray-ground-propagation-loss-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/uan_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/uan_channel.html new file mode 100644 index 00000000..4e17dfd4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/uan_channel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.uan_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.uan_channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3channel import NS3BaseChannel 
    +
    +@clsinit_copy
    +
    [docs]class NS3UanChannel(NS3BaseChannel): + _rtype = "ns3::UanChannel" + + @classmethod + def _register_attributes(cls): + + attr_id = Attribute("Id", + "The id (unique integer) of this Channel.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_id) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3UanChannel, self).__init__(ec, guid) + self._home = "ns3-uan-channel-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_client.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_client.html new file mode 100644 index 00000000..a86a67d3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_client.html @@ -0,0 +1,201 @@ + + + + + + + + nepi.resources.ns3.classes.udp_client — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.udp_client

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3application import NS3BaseApplication 
    +
    +@clsinit_copy
    +
    [docs]class NS3UdpClient(NS3BaseApplication): + _rtype = "ns3::UdpClient" + + @classmethod + def _register_attributes(cls): + + attr_maxpackets = Attribute("MaxPackets", + "The maximum number of packets the application will send", + type = Types.Integer, + default = "100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxpackets) + + attr_interval = Attribute("Interval", + "The time to wait between packets", + type = Types.String, + default = "+1000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_interval) + + attr_remoteaddress = Attribute("RemoteAddress", + "The destination Address of the outbound packets", + type = Types.String, + default = "00-00-00", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_remoteaddress) + + attr_remoteport = Attribute("RemotePort", + "The destination port of the outbound packets", + type = Types.Integer, + default = "100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_remoteport) + + attr_packetsize = Attribute("PacketSize", + "Size of packets generated. The minimum packet size is 12 bytes which is the size of the header carrying the sequence number and the time stamp.", + type = Types.Integer, + default = "1024", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_packetsize) + + attr_starttime = Attribute("StartTime", + "Time at which the application will start", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_starttime) + + attr_stoptime = Attribute("StopTime", + "Time at which the application will stop", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stoptime) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3UdpClient, self).__init__(ec, guid) + self._home = "ns3-udp-client-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_client.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_client.html new file mode 100644 index 00000000..245eb6d0 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_client.html @@ -0,0 +1,206 @@ + + + + + + + + nepi.resources.ns3.classes.udp_echo_client — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.udp_echo_client

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3application import NS3BaseApplication 
    +
    +@clsinit_copy
    +
    [docs]class NS3UdpEchoClient(NS3BaseApplication): + _rtype = "ns3::UdpEchoClient" + + @classmethod + def _register_attributes(cls): + + attr_maxpackets = Attribute("MaxPackets", + "The maximum number of packets the application will send", + type = Types.Integer, + default = "100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxpackets) + + attr_interval = Attribute("Interval", + "The time to wait between packets", + type = Types.String, + default = "+1000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_interval) + + attr_remoteaddress = Attribute("RemoteAddress", + "The destination Address of the outbound packets", + type = Types.String, + default = "00-00-00", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_remoteaddress) + + attr_remoteport = Attribute("RemotePort", + "The destination port of the outbound packets", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_remoteport) + + attr_packetsize = Attribute("PacketSize", + "Size of echo data in outbound packets", + type = Types.Integer, + default = "100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_packetsize) + + attr_starttime = Attribute("StartTime", + "Time at which the application will start", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_starttime) + + attr_stoptime = Attribute("StopTime", + "Time at which the application will stop", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stoptime) + + + + @classmethod + def _register_traces(cls): + + tx = Trace("Tx", "A new packet is created and is sent") + + cls._register_trace(tx) + + + + def __init__(self, ec, guid): + super(NS3UdpEchoClient, self).__init__(ec, guid) + self._home = "ns3-udp-echo-client-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_server.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_server.html new file mode 100644 index 00000000..582ce26d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_server.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.udp_echo_server — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.udp_echo_server

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3application import NS3BaseApplication 
    +
    +@clsinit_copy
    +
    [docs]class NS3UdpEchoServer(NS3BaseApplication): + _rtype = "ns3::UdpEchoServer" + + @classmethod + def _register_attributes(cls): + + attr_port = Attribute("Port", + "Port on which we listen for incoming packets.", + type = Types.Integer, + default = "9", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_port) + + attr_starttime = Attribute("StartTime", + "Time at which the application will start", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_starttime) + + attr_stoptime = Attribute("StopTime", + "Time at which the application will stop", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stoptime) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3UdpEchoServer, self).__init__(ec, guid) + self._home = "ns3-udp-echo-server-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_l4protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_l4protocol.html new file mode 100644 index 00000000..9a2086a8 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_l4protocol.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.udp_l4protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.udp_l4protocol

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3UdpL4Protocol(NS3Base): + _rtype = "ns3::UdpL4Protocol" + + @classmethod + def _register_attributes(cls): + + attr_protocolnumber = Attribute("ProtocolNumber", + "The Ip protocol number.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_protocolnumber) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3UdpL4Protocol, self).__init__(ec, guid) + self._home = "ns3-udp-l4protocol-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_server.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_server.html new file mode 100644 index 00000000..8688d338 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_server.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.classes.udp_server — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.udp_server

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3application import NS3BaseApplication 
    +
    +@clsinit_copy
    +
    [docs]class NS3UdpServer(NS3BaseApplication): + _rtype = "ns3::UdpServer" + + @classmethod + def _register_attributes(cls): + + attr_port = Attribute("Port", + "Port on which we listen for incoming packets.", + type = Types.Integer, + default = "100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_port) + + attr_packetwindowsize = Attribute("PacketWindowSize", + "The size of the window used to compute the packet loss. This value should be a multiple of 8.", + type = Types.Integer, + default = "32", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_packetwindowsize) + + attr_starttime = Attribute("StartTime", + "Time at which the application will start", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_starttime) + + attr_stoptime = Attribute("StopTime", + "Time at which the application will stop", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stoptime) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3UdpServer, self).__init__(ec, guid) + self._home = "ns3-udp-server-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_trace_client.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_trace_client.html new file mode 100644 index 00000000..266ecd7d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_trace_client.html @@ -0,0 +1,181 @@ + + + + + + + + nepi.resources.ns3.classes.udp_trace_client — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.udp_trace_client

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3application import NS3BaseApplication 
    +
    +@clsinit_copy
    +
    [docs]class NS3UdpTraceClient(NS3BaseApplication): + _rtype = "ns3::UdpTraceClient" + + @classmethod + def _register_attributes(cls): + + attr_remoteaddress = Attribute("RemoteAddress", + "The destination Address of the outbound packets", + type = Types.String, + default = "00-00-00", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_remoteaddress) + + attr_remoteport = Attribute("RemotePort", + "The destination port of the outbound packets", + type = Types.Integer, + default = "100", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_remoteport) + + attr_maxpacketsize = Attribute("MaxPacketSize", + "The maximum size of a packet (including the SeqTsHeader, 12 bytes).", + type = Types.Integer, + default = "1024", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_maxpacketsize) + + attr_starttime = Attribute("StartTime", + "Time at which the application will start", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_starttime) + + attr_stoptime = Attribute("StopTime", + "Time at which the application will stop", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stoptime) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3UdpTraceClient, self).__init__(ec, guid) + self._home = "ns3-udp-trace-client-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/v4ping.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/v4ping.html new file mode 100644 index 00000000..3dd63cd5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/v4ping.html @@ -0,0 +1,196 @@ + + + + + + + + nepi.resources.ns3.classes.v4ping — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.v4ping

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3application import NS3BaseApplication 
    +
    +@clsinit_copy
    +
    [docs]class NS3V4Ping(NS3BaseApplication): + _rtype = "ns3::V4Ping" + + @classmethod + def _register_attributes(cls): + + attr_remote = Attribute("Remote", + "The address of the machine we want to ping.", + type = Types.String, + default = "102.102.102.102", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_remote) + + attr_verbose = Attribute("Verbose", + "Produce usual output.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_verbose) + + attr_interval = Attribute("Interval", + "Wait interval seconds between sending each packet.", + type = Types.String, + default = "+1000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_interval) + + attr_size = Attribute("Size", + "The number of data bytes to be sent, real packet will be 8 (ICMP) + 20 (IP) bytes longer.", + type = Types.Integer, + default = "56", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_size) + + attr_starttime = Attribute("StartTime", + "Time at which the application will start", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_starttime) + + attr_stoptime = Attribute("StopTime", + "Time at which the application will stop", + type = Types.String, + default = "+0.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stoptime) + + + + @classmethod + def _register_traces(cls): + + rtt = Trace("Rtt", "The rtt calculated by the ping.") + + cls._register_trace(rtt) + + + + def __init__(self, ec, guid): + super(NS3V4Ping, self).__init__(ec, guid) + self._home = "ns3-v4ping-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/virtual_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/virtual_net_device.html new file mode 100644 index 00000000..82adaa9a --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/virtual_net_device.html @@ -0,0 +1,162 @@ + + + + + + + + nepi.resources.ns3.classes.virtual_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.virtual_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3VirtualNetDevice(NS3BaseNetDevice): + _rtype = "ns3::VirtualNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_mtu = Attribute("Mtu", + "The MAC-level Maximum Transmission Unit", + type = Types.Integer, + default = "1500", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + + + @classmethod + def _register_traces(cls): + + mactx = Trace("MacTx", "Trace source indicating a packet has arrived for transmission by this device") + + cls._register_trace(mactx) + + macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a promiscuous trace,") + + cls._register_trace(macpromiscrx) + + macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack. This is a non-promiscuous trace,") + + cls._register_trace(macrx) + + sniffer = Trace("Sniffer", "Trace source simulating a non-promiscuous packet sniffer attached to the device") + + cls._register_trace(sniffer) + + promiscsniffer = Trace("PromiscSniffer", "Trace source simulating a promiscuous packet sniffer attached to the device") + + cls._register_trace(promiscsniffer) + + + + def __init__(self, ec, guid): + super(NS3VirtualNetDevice, self).__init__(ec, guid) + self._home = "ns3-virtual-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/waypoint_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/waypoint_mobility_model.html new file mode 100644 index 00000000..54460890 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/waypoint_mobility_model.html @@ -0,0 +1,186 @@ + + + + + + + + nepi.resources.ns3.classes.waypoint_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.waypoint_mobility_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3WaypointMobilityModel(NS3BaseMobilityModel): + _rtype = "ns3::WaypointMobilityModel" + + @classmethod + def _register_attributes(cls): + + attr_waypointsleft = Attribute("WaypointsLeft", + "The number of waypoints remaining.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_waypointsleft) + + attr_lazynotify = Attribute("LazyNotify", + "Only call NotifyCourseChange when position is calculated.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_lazynotify) + + attr_initialpositioniswaypoint = Attribute("InitialPositionIsWaypoint", + "Calling SetPosition with no waypoints creates a waypoint.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_initialpositioniswaypoint) + + attr_position = Attribute("Position", + "The current position of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved) + + cls._register_attribute(attr_position) + + attr_velocity = Attribute("Velocity", + "The current velocity of the mobility model.", + type = Types.String, + default = "0:0:0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_velocity) + + + + @classmethod + def _register_traces(cls): + + coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed") + + cls._register_trace(coursechange) + + + + def __init__(self, ec, guid): + super(NS3WaypointMobilityModel, self).__init__(ec, guid) + self._home = "ns3-waypoint-mobility-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/wifi_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/wifi_net_device.html new file mode 100644 index 00000000..86375c83 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/wifi_net_device.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.wifi_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.wifi_net_device

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifinetdevice import NS3BaseWifiNetDevice 
    +
    +@clsinit_copy
    +
    [docs]class NS3WifiNetDevice(NS3BaseWifiNetDevice): + _rtype = "ns3::WifiNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_mtu = Attribute("Mtu", + "The MAC-level Maximum Transmission Unit", + type = Types.Integer, + default = "2296", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_mtu) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3WifiNetDevice, self).__init__(ec, guid) + self._home = "ns3-wifi-net-device-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_error_rate_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_error_rate_model.html new file mode 100644 index 00000000..f4c77474 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_error_rate_model.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.yans_error_rate_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.yans_error_rate_model

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3errorratemodel import NS3BaseErrorRateModel 
    +
    +@clsinit_copy
    +
    [docs]class NS3YansErrorRateModel(NS3BaseErrorRateModel): + _rtype = "ns3::YansErrorRateModel" + + @classmethod + def _register_attributes(cls): + pass + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3YansErrorRateModel, self).__init__(ec, guid) + self._home = "ns3-yans-error-rate-model-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_channel.html new file mode 100644 index 00000000..658f1b87 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_channel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.yans_wifi_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.yans_wifi_channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifichannel import NS3BaseWifiChannel 
    +
    +@clsinit_copy
    +
    [docs]class NS3YansWifiChannel(NS3BaseWifiChannel): + _rtype = "ns3::YansWifiChannel" + + @classmethod + def _register_attributes(cls): + + attr_id = Attribute("Id", + "The id (unique integer) of this Channel.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.NoWrite) + + cls._register_attribute(attr_id) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3YansWifiChannel, self).__init__(ec, guid) + self._home = "ns3-yans-wifi-channel-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_phy.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_phy.html new file mode 100644 index 00000000..6cb03971 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_phy.html @@ -0,0 +1,344 @@ + + + + + + + + nepi.resources.ns3.classes.yans_wifi_phy — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.classes.yans_wifi_phy

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.ns3.ns3wifiphy import NS3BaseWifiPhy 
    +
    +@clsinit_copy
    +
    [docs]class NS3YansWifiPhy(NS3BaseWifiPhy): + _rtype = "ns3::YansWifiPhy" + + @classmethod + def _register_attributes(cls): + + attr_energydetectionthreshold = Attribute("EnergyDetectionThreshold", + "The energy of a received signal should be higher than this threshold (dbm) to allow the PHY layer to detect the signal.", + type = Types.Double, + default = "-96", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_energydetectionthreshold) + + attr_ccamode1threshold = Attribute("CcaMode1Threshold", + "The energy of a received signal should be higher than this threshold (dbm) to allow the PHY layer to declare CCA BUSY state", + type = Types.Double, + default = "-99", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ccamode1threshold) + + attr_txgain = Attribute("TxGain", + "Transmission gain (dB).", + type = Types.Double, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_txgain) + + attr_rxgain = Attribute("RxGain", + "Reception gain (dB).", + type = Types.Double, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rxgain) + + attr_txpowerlevels = Attribute("TxPowerLevels", + "Number of transmission power levels available between TxPowerStart and TxPowerEnd included.", + type = Types.Integer, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_txpowerlevels) + + attr_txpowerend = Attribute("TxPowerEnd", + "Maximum available transmission level (dbm).", + type = Types.Double, + default = "16.0206", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_txpowerend) + + attr_txpowerstart = Attribute("TxPowerStart", + "Minimum available transmission level (dbm).", + type = Types.Double, + default = "16.0206", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_txpowerstart) + + attr_rxnoisefigure = Attribute("RxNoiseFigure", + "Loss (dB) in the Signal-to-Noise-Ratio due to non-idealities in the receiver. According to Wikipedia (http://en.wikipedia.org/wiki/Noise_figure), this is \"the difference in decibels (dB) between the noise output of the actual receiver to the noise output of an ideal receiver with the same overall gain and bandwidth when the receivers are connected to sources at the standard noise temperature T0 (usually 290 K)\". For", + type = Types.Double, + default = "7", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rxnoisefigure) + + attr_channelswitchdelay = Attribute("ChannelSwitchDelay", + "Delay between two short frames transmitted on different frequencies.", + type = Types.String, + default = "+250000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_channelswitchdelay) + + attr_channelnumber = Attribute("ChannelNumber", + "Channel center frequency = Channel starting frequency + 5 MHz * nch", + type = Types.Integer, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_channelnumber) + + attr_frequency = Attribute("Frequency", + "The operating frequency.", + type = Types.Integer, + default = "2407", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_frequency) + + attr_transmitters = Attribute("Transmitters", + "The number of transmitters.", + type = Types.Integer, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_transmitters) + + attr_recievers = Attribute("Recievers", + "The number of recievers.", + type = Types.Integer, + default = "1", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_recievers) + + attr_shortguardenabled = Attribute("ShortGuardEnabled", + "Whether or not short guard interval is enabled.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_shortguardenabled) + + attr_ldpcenabled = Attribute("LdpcEnabled", + "Whether or not LDPC is enabled.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ldpcenabled) + + attr_stbcenabled = Attribute("STBCEnabled", + "Whether or not STBC is enabled.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_stbcenabled) + + attr_greenfieldenabled = Attribute("GreenfieldEnabled", + "Whether or not STBC is enabled.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_greenfieldenabled) + + attr_channelbonding = Attribute("ChannelBonding", + "Whether 20MHz or 40MHz.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_channelbonding) + + + + @classmethod + def _register_traces(cls): + + phytxbegin = Trace("PhyTxBegin", "Trace source indicating a packet has begun transmitting over the channel medium") + + cls._register_trace(phytxbegin) + + phytxend = Trace("PhyTxEnd", "Trace source indicating a packet has been completely transmitted over the channel. NOTE: the only official WifiPhy implementation available to this date (YansWifiPhy) never fires this trace source.") + + cls._register_trace(phytxend) + + phytxdrop = Trace("PhyTxDrop", "Trace source indicating a packet has been dropped by the device during transmission") + + cls._register_trace(phytxdrop) + + phyrxbegin = Trace("PhyRxBegin", "Trace source indicating a packet has begun being received from the channel medium by the device") + + cls._register_trace(phyrxbegin) + + phyrxend = Trace("PhyRxEnd", "Trace source indicating a packet has been completely received from the channel medium by the device") + + cls._register_trace(phyrxend) + + phyrxdrop = Trace("PhyRxDrop", "Trace source indicating a packet has been dropped by the device during reception") + + cls._register_trace(phyrxdrop) + + monitorsnifferrx = Trace("MonitorSnifferRx", "Trace source simulating a wifi device in monitor mode sniffing all received frames") + + cls._register_trace(monitorsnifferrx) + + monitorsniffertx = Trace("MonitorSnifferTx", "Trace source simulating the capability of a wifi device in monitor mode to sniff all frames being transmitted") + + cls._register_trace(monitorsniffertx) + + + + def __init__(self, ec, guid): + super(NS3YansWifiPhy, self).__init__(ec, guid) + self._home = "ns3-yans-wifi-phy-%s" % self.guid
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3application.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3application.html new file mode 100644 index 00000000..755f4783 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3application.html @@ -0,0 +1,181 @@ + + + + + + + + nepi.resources.ns3.ns3application — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3application

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseApplication(NS3Base): + _rtype = "abstract::ns3::Application" + + def __init__(self, ec, guid): + super(NS3BaseApplication, self).__init__(ec, guid) + self._node = None + + @property +
    [docs] def node(self): + if not self._node: + from nepi.resources.ns3.ns3node import NS3BaseNode + nodes = self.get_connected(NS3BaseNode.get_rtype()) + + if not nodes: + msg = "Application not connected to node" + self.error(msg) + raise RuntimeError, msg + + self._node = nodes[0] + + return self._node +
    + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.node) + return rms + + def _connect_object(self): + node = self.node + if node.uuid not in self.connected: + self.simulation.invoke(node.uuid, "AddApplication", self.uuid) + self._connected.add(node.uuid) + +
    [docs] def do_stop(self): + if self.state == ResourceState.STARTED: + # No need to do anything, simulation.Destroy() will stop every object + self.info("Stopping command '%s'" % command) + self.simulation.invoke(self.uuid, "Stop") + self.set_stopped() +
    +
    [docs] def do_start(self): + if self.simulation.state < ResourceState.STARTED: + self.debug("---- RESCHEDULING START ----" ) + self.ec.schedule(self.reschedule_delay, self.start) + else: + super(NS3BaseApplication, self).do_start() + self._start_time = self.simulation.start_time +
    + @property +
    [docs] def state(self): + if self._state == ResourceState.STARTED: + try: + is_running = self.simulation.invoke(self.uuid, "isAppRunning") + + if not is_running: + self.set_stopped() + except: + msg = "Application failed. Can not retrieve state" + out = "" + + import traceback + err = traceback.format_exc() + self.error(msg, out, err) + self.do_fail() + + return self._state +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3arpl3protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3arpl3protocol.html new file mode 100644 index 00000000..ad7db8ed --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3arpl3protocol.html @@ -0,0 +1,137 @@ + + + + + + + + nepi.resources.ns3.ns3arpl3protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3arpl3protocol

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseArpL3Protocol(NS3Base): + _rtype = "abstract::ns3::ArpL3Protocol" + + @property +
    [docs] def node(self): + from nepi.resources.ns3.ns3node import NS3BaseNode + nodes = self.get_connected(NS3BaseNode.get_rtype()) + + if not nodes: + msg = "ArpL3Protocol not connected to node" + self.error(msg) + raise RuntimeError, msg + + return nodes[0] +
    + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.simulation) + return rms + + def _connect_object(self): + pass
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3base.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3base.html new file mode 100644 index 00000000..dd54a0c9 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3base.html @@ -0,0 +1,257 @@ + + + + + + + + nepi.resources.ns3.ns3base — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3base

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.execution.attribute import Flags
    +from nepi.execution.trace import TraceAttr
    +
    +@clsinit_copy
    +
    [docs]class NS3Base(ResourceManager): + _rtype = "abstract::ns3::Object" + _platform = "ns3" + + def __init__(self, ec, guid): + super(NS3Base, self).__init__(ec, guid) + self._uuid = None + self._connected = set() + self._trace_filename = dict() + self._node = None + + @property +
    [docs] def connected(self): + return self._connected +
    + @property +
    [docs] def uuid(self): + return self._uuid +
    + @property +
    [docs] def simulation(self): + return self.node.simulation +
    + @property +
    [docs] def node(self): + if not self._node: + from nepi.resources.ns3.ns3node import NS3BaseNode + nodes = self.get_connected(NS3BaseNode.get_rtype()) + if nodes: self._node = nodes[0] + + return self._node +
    +
    [docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + filename = self._trace_filename.get(name) + if not filename: + self.error("Can not resolve trace %s. Did you enabled it?" % name) + return "" + + return self.simulation.trace(filename, attr, block, offset) +
    + @property + def _rms_to_wait(self): + """ Returns the collection of ns-3 RMs that this RM needs to + wait for before start + + This method should be overriden to wait for other ns-3 + objects to be deployed before proceeding with the deployment + + """ + rms = set() + node = self.node + if node: rms.add(node) + return rms + + def _instantiate_object(self): + if self.uuid: + return + + kwargs = dict() + for attr in self._attrs.values(): + if not ( attr.has_flag(Flags.Construct) and attr.has_changed ): + continue + + kwargs[attr.name] = attr._value + + self._uuid = self.simulation.factory(self.get_rtype(), **kwargs) + + def _configure_object(self): + pass + + def _connect_object(self): + node = self.node + if node and node.uuid not in self.connected: + self.simulation.invoke(node.uuid, "AggregateObject", self.uuid) + self._connected.add(node.uuid) + + def _wait_rms(self): + """ Returns True if dependent RMs are not yer READY, False otherwise""" + for rm in self._rms_to_wait: + if rm.state < ResourceState.READY: + return True + return False + +
    [docs] def do_provision(self): + self._instantiate_object() + self._connect_object() + self._configure_object() + + self.info("Provisioning finished") + + super(NS3Base, self).do_provision() +
    +
    [docs] def do_deploy(self): + if self._wait_rms(): + self.debug("---- RESCHEDULING DEPLOY ----" ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def do_start(self): + if self.state == ResourceState.READY: + # No need to do anything, simulation.Run() will start every object + self.info("Starting") + self.set_started() + else: + msg = "Failed" + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def do_stop(self): + if self.state == ResourceState.STARTED: + # No need to do anything, simulation.Destroy() will stop every object + self.info("Stopping") + self.set_stopped() +
    + @property +
    [docs] def state(self): + return self._state +
    +
    [docs] def get(self, name): + if self.state in [ResourceState.READY, ResourceState.STARTED] and \ + self.has_flag(name, Flags.Reserved) and \ + not self.has_flag(name, Flags.NoRead): + return self.simulation.ns3_get(self.uuid, name) + else: + value = super(NS3Base, self).get(name) + + return value +
    +
    [docs] def set(self, name, value): + if self.state in [ResourceState.READY, ResourceState.STARTED] and \ + self.has_flag(name, Flags.Reserved) and \ + not (self.has_flag(Flags.NoWrite) or self.has_flag(name, Flags.Design)): + self.simulation.ns3_set(self.uuid, name, value) + + value = super(NS3Base, self).set(name, value) + + return value +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ccndceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ccndceapplication.html new file mode 100644 index 00000000..273de635 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ccndceapplication.html @@ -0,0 +1,212 @@ + + + + + + + + nepi.resources.ns3.ns3ccndceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3ccndceapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.ns3.ns3dceapplication import NS3BaseDceApplication
    +
    +import os
    +import threading
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseCCNDceApplication(NS3BaseDceApplication): + _rtype = "abstract::ns3::CCNDceApplication" + + # Lock used to synchronize usage of CcnClientHelper + ccn_client_lock = threading.Lock() + _ccn_client_helper_uuid = None + + @property +
    [docs] def ccn_client_helper_uuid(self): + if not self._ccn_client_helper_uuid: + self._ccn_client_helper_uuid = self.simulation.create("CcnClientHelper") + return self._ccn_client_helper_uuid +
    + def _instantiate_object(self): + pass + + def _connect_object(self): + node = self.node + if node.uuid not in self.connected: + self._connected.add(node.uuid) + + # Preventing concurrent access to the DceApplicationHelper + # from different DceApplication RMs + with self.ccn_client_lock: + self.simulation.invoke( + self.ccn_client_helper_uuid, + "ResetArguments") + + self.simulation.invoke( + self.ccn_client_helper_uuid, + "ResetEnvironment") + + self.simulation.invoke( + self.ccn_client_helper_uuid, + "SetBinary", self.get("binary")) + + self.simulation.invoke( + self.ccn_client_helper_uuid, + "SetStackSize", self.get("stackSize")) + + arguments = self.get("arguments") + if arguments: + for arg in map(str.strip, arguments.split(";")): + self.simulation.invoke( + self.ccn_client_helper_uuid, + "AddArgument", arg) + + environment = self.get("environment") + if environment: + for env in map(str.strip, environment.split(";")): + key, val = env.split("=") + self.simulation.invoke( + self.ccn_client_helper_uuid, + "AddEnvironment", key, val) + + if self.has_attribute("files"): + files = self.get("files") + if files: + for file in map(str.strip, files.split(";")): + remotepath, dcepath = file.split("=") + localpath = os.path.join(self.simulation.app_home, + os.path.basename(remotepath)) + self.simulation.invoke( + self.ccn_client_helper_uuid, + "AddFile", localpath, dcepath) + + if self.has_attribute("stdinFile"): + stdinfile = self.get("stdinFile") + if stdinfile: + # stdinfile might be an empty text that should be set as + # stdin + self.simulation.invoke( + self.ccn_client_helper_uuid, + "SetStdinFile", stdinfile) + + apps_uuid = self.simulation.invoke( + self.ccn_client_helper_uuid, + "InstallInNode", self.node.uuid) + + """ + container_uuid = self.simulation.create("NodeContainer") + self.simulation.invoke(container_uuid, "Add", self.node.uuid) + apps_uuid = self.simulation.invoke( + self.ccn_client_helper_uuid, + "Install", container_uuid) + """ + + self._uuid = self.simulation.invoke(apps_uuid, "Get", 0) + + if self.has_changed("StartTime"): + self.simulation.ns3_set(self.uuid, "StartTime", self.get("StartTime")) + + if self.has_changed("StopTime"): + self.simulation.ns3_set(self.uuid, "StopTime", self.get("StopTime")) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3channel.html new file mode 100644 index 00000000..cc8246d0 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3channel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.ns3channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseChannel(NS3Base): + _rtype = "abstract::ns3::Channel" + + @property +
    [docs] def simulation(self): + return self.devices[0].node.simulation +
    + @property +
    [docs] def devices(self): + from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice + devices = self.get_connected(NS3BaseNetDevice.get_rtype()) + + if not devices: + msg = "Channel not connected to devices" + self.error(msg) + raise RuntimeError, msg + + return devices +
    + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.simulation) + return rms + + def _connect_object(self): + pass +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3client.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3client.html new file mode 100644 index 00000000..7e94ddcc --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3client.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.ns3client — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3client

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +
    [docs]class NS3Client(object): + """ Common Interface for NS3 client classes """ + def __init__(self): + super(NS3Client, self).__init__() + +
    [docs] def create(self, *args, **kwargs): + pass +
    +
    [docs] def factory(self, *args, **kwargs): + pass +
    +
    [docs] def invoke(self, *args, **kwargs): + pass +
    +
    [docs] def set(self, *args, **kwargs): + pass +
    +
    [docs] def get(self, *args, **kwargs): + pass +
    +
    [docs] def flush(self, *args, **kwargs): + pass +
    +
    [docs] def start(self, *args, **kwargs): + pass +
    +
    [docs] def stop(self, *args, **kwargs): + pass +
    +
    [docs] def shutdown(self, *args, **kwargs): + pass +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dceapplication.html new file mode 100644 index 00000000..87795b99 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dceapplication.html @@ -0,0 +1,272 @@ + + + + + + + + nepi.resources.ns3.ns3dceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3dceapplication

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.ns3.ns3application import NS3BaseApplication
    +from nepi.execution.trace import TraceAttr
    +
    +from nepi.resources.ns3.ns3wrapper import SIMULATOR_UUID
    +
    +import os
    +import time
    +import threading
    +        
    +@clsinit_copy
    +
    [docs]class NS3BaseDceApplication(NS3BaseApplication): + _rtype = "abstract::ns3::DceApplication" + + @classmethod + def _register_attributes(cls): + binary = Attribute("binary", + "Name of binary to execute", + flags = Flags.Design) + + stack_size = Attribute("stackSize", + "Stack Size for DCE", + type = Types.Integer, + default = 1<<20, + flags = Flags.Design) + + arguments = Attribute("arguments", + "Semi-colon separated list of arguments for the application", + flags = Flags.Design) + + environment = Attribute("environment", + "Semi-colon separated list of 'key=value' pairs to set as " + "DCE environment variables.", + flags = Flags.Design) + + use_dlm = Attribute("useDlmLoader", + "Use ns3::DlmLoaderFactory as library loader", + type = Types.Bool, + flags = Flags.Design) + + starttime = Attribute("StartTime", + "Time at which the application will start", + default = "+0.0ns", + flags = Flags.Reserved | Flags.Construct) + + stoptime = Attribute("StopTime", + "Time at which the application will stop", + default = "+0.0ns", + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(binary) + cls._register_attribute(stack_size) + cls._register_attribute(arguments) + cls._register_attribute(environment) + cls._register_attribute(use_dlm) + cls._register_attribute(stoptime) + cls._register_attribute(starttime) + + def __init__(self, ec, guid): + super(NS3BaseDceApplication, self).__init__(ec, guid) + self._pid = None + + @property +
    [docs] def pid(self): + return self._pid +
    + def _instantiate_object(self): + pass + + def _connect_object(self): + node = self.node + if node.uuid not in self.connected: + self._connected.add(node.uuid) + + # Preventing concurrent access to the DceApplicationHelper + # from different DceApplication RMs + dce_helper = self.simulation.dce_helper + + with dce_helper.dce_application_lock: + dce_app_uuid = dce_helper.dce_application_uuid + + self.simulation.invoke(dce_app_uuid, "ResetArguments") + + self.simulation.invoke(dce_app_uuid, "ResetEnvironment") + + self.simulation.invoke(dce_app_uuid, + "SetBinary", self.get("binary")) + + self.simulation.invoke(dce_app_uuid, + "SetStackSize", self.get("stackSize")) + + arguments = self.get("arguments") + if arguments: + for arg in map(str.strip, arguments.split(";")): + self.simulation.invoke(dce_app_uuid, + "AddArgument", arg) + + environment = self.get("environment") + if environment: + for env in map(str.strip, environment.split(";")): + key, val = env.split("=") + self.simulation.invoke(dce_app_uuid, + "AddEnvironment", key, val) + + apps_uuid = self.simulation.invoke(dce_app_uuid, + "InstallInNode", self.node.uuid) + + self._uuid = self.simulation.invoke(apps_uuid, "Get", 0) + + if self.has_changed("StartTime"): + self.simulation.ns3_set(self.uuid, "StartTime", self.get("StartTime")) + + if self.has_changed("StopTime"): + self.simulation.ns3_set(self.uuid, "StopTime", self.get("StopTime")) + +
    [docs] def do_stop(self): + if self.state == ResourceState.STARTED: + # No need to do anything, simulation.Destroy() will stop every object + self.info("Stopping command '%s'" % command) + self.simulation.invoke(self.uuid, "Stop") + self.set_stopped() +
    +
    [docs] def do_start(self): + if self.simulation.state < ResourceState.STARTED: + self.debug("---- RESCHEDULING START ----" ) + self.ec.schedule(self.reschedule_delay, self.start) + else: + is_app_started = self.simulation.invoke(self.uuid, "isAppStarted") + + if is_app_started or self.simulation.state > ResourceState.STARTED: + super(NS3BaseApplication, self).do_start() + self._start_time = self.simulation.start_time + else: + # Reschedule until dce application is actually started + self.debug("---- RESCHEDULING START ----" ) + self.ec.schedule(self.reschedule_delay, self.start) +
    +
    [docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + self._configure_traces() + return super(NS3BaseDceApplication, self).trace(name, attr = attr, + block = block, offset = offset) +
    + def _configure_traces(self): + if self.pid is not None: + return + + # Using lock to prevent concurrent access to the DceApplicationHelper + # from different DceApplication RMs + dce_helper = self.simulation.dce_helper + + with dce_helper.dce_application_lock: + dce_app_uuid = dce_helper.dce_application_uuid + + self._pid = self.simulation.invoke(dce_app_uuid, + "GetPid", self.uuid) + + node_id = self.node.node_id + self._trace_filename["stdout"] = "files-%s/var/log/%s/stdout" % (node_id, self.pid) + self._trace_filename["stderr"] = "files-%s/var/log/%s/stderr" % (node_id, self.pid) + self._trace_filename["status"] = "files-%s/var/log/%s/status" % (node_id, self.pid) + self._trace_filename["cmdline"] = "files-%s/var/log/%s/cmdline" % (node_id, self.pid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dcehelper.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dcehelper.html new file mode 100644 index 00000000..6c104f30 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dcehelper.html @@ -0,0 +1,149 @@ + + + + + + + + nepi.resources.ns3.ns3dcehelper — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3dcehelper

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import os
    +import time
    +import threading
    +        
    +
    [docs]class NS3DceHelper(object): + def __init__(self, simulation): + self.simulation = simulation + + # Lock used to synchronize usage of DceManagerHelper + self._dce_manager_lock = threading.Lock() + # Lock used to synchronize usage of DceApplicationHelper + self._dce_application_lock = threading.Lock() + + self._dce_manager_uuid = None + self._dce_application_uuid = None + + @property +
    [docs] def dce_manager_uuid(self): + if not self._dce_manager_uuid: + self._dce_manager_uuid = \ + self.simulation.create("DceManagerHelper") + + return self._dce_manager_uuid +
    + @property +
    [docs] def dce_application_uuid(self): + if not self._dce_application_uuid: + self._dce_application_uuid = \ + self.simulation.create("DceApplicationHelper") + + return self._dce_application_uuid +
    + @property +
    [docs] def dce_manager_lock(self): + return self._dce_manager_lock +
    + @property +
    [docs] def dce_application_lock(self): + return self._dce_application_lock +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errormodel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errormodel.html new file mode 100644 index 00000000..08e27212 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errormodel.html @@ -0,0 +1,140 @@ + + + + + + + + nepi.resources.ns3.ns3errormodel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3errormodel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseErrorModel(NS3Base): + _rtype = "abstract::ns3::ErrorModel" + + @property +
    [docs] def device(self): + from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice + devices = self.get_connected(NS3BaseNetDevice.get_rtype()) + + if not devices: + msg = "ErrorModel not connected to device" + self.error(msg) + raise RuntimeError, msg + + return devices[0] +
    + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.device) + return rms + + def _connect_object(self): + device = self.device + if device.uuid not in self.connected: + self.simulation.invoke(device.uuid, "SetReceiveErrorModel", self.uuid) + self._connected.add(device.uuid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errorratemodel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errorratemodel.html new file mode 100644 index 00000000..7a81fc4c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errorratemodel.html @@ -0,0 +1,144 @@ + + + + + + + + nepi.resources.ns3.ns3errorratemodel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3errorratemodel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseErrorRateModel(NS3Base): + _rtype = "abstract::ns3::ErrorRateModel" + + @property +
    [docs] def node(self): + return self.phy.node +
    + @property +
    [docs] def phy(self): + from nepi.resources.ns3.ns3wifiphy import NS3BaseWifiPhy + phys = self.get_connected(NS3BaseWifiPhy.get_rtype()) + + if not phys: + msg = "ErrorRateModel not connected to phy" + self.error(msg) + raise RuntimeError, msg + + return phys[0] +
    + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.phy) + return rms + + def _connect_object(self): + phy = self.phy + if phy.uuid not in self.connected: + self.simulation.invoke(phy.uuid, "SetErrorRateModel", self.uuid) + self._connected.add(phy.uuid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3fdnetdevice.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3fdnetdevice.html new file mode 100644 index 00000000..d220680b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3fdnetdevice.html @@ -0,0 +1,149 @@ + + + + + + + + nepi.resources.ns3.ns3fdnetdevice — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3fdnetdevice

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseFdNetDevice(NS3BaseNetDevice): + _rtype = "abstract::ns3::FdNetDevice" + + @property + def _rms_to_wait(self): + rms = set([self.node]) + return rms + + def _configure_mac_address(self): + # The wifimac is the one responsible for + # configuring the MAC address + pass + + def _connect_object(self): + node = self.node + if node and node.uuid not in self.connected: + self.simulation.invoke(node.uuid, "AddDevice", self.uuid) + self._connected.add(node.uuid) + + def _instantiate_object(self): + """ just validate that the simulator is in real time + mode, otherwise it is not going to work + """ + + mode = self.simulation.get("simulatorImplementationType") + if mode != "ns3::RealtimeSimulatorImpl": + msg = "The simulation must run in real time!!" + self.error(msg) + raise RuntimeError, msg + + super(NS3BaseFdNetDevice, self)._instantiate_object() + +
    [docs] def recv_fd(self): + address = self.simulation.invoke(self.uuid, "recvFD") + return address +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3icmpv4l4protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3icmpv4l4protocol.html new file mode 100644 index 00000000..08b9cac6 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3icmpv4l4protocol.html @@ -0,0 +1,134 @@ + + + + + + + + nepi.resources.ns3.ns3icmpv4l4protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3icmpv4l4protocol

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseIcmpv4L4Protocol(NS3Base): + _rtype = "abstract::ns3::Icmpv4L4Protocol" + + @property +
    [docs] def node(self): + from nepi.resources.ns3.ns3node import NS3BaseNode + nodes = self.get_connected(NS3BaseNode.get_rtype()) + + if not nodes: + msg = "Icmp4L4Protocol not connected to node" + self.error(msg) + raise RuntimeError, msg + + return nodes[0] +
    + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.node) + return rms +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ipv4l3protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ipv4l3protocol.html new file mode 100644 index 00000000..af335aaf --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ipv4l3protocol.html @@ -0,0 +1,157 @@ + + + + + + + + nepi.resources.ns3.ns3ipv4l3protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3ipv4l3protocol

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseIpv4L3Protocol(NS3Base): + _rtype = "abstract::ns3::Ipv4L3Protocol" + + def __init__(self, ec, guid): + super(NS3BaseIpv4L3Protocol, self).__init__(ec, guid) + self.list_routing_uuid = None + self.static_routing_uuid = None + self.global_routing_uuid = None + + @property +
    [docs] def node(self): + from nepi.resources.ns3.ns3node import NS3BaseNode + nodes = self.get_connected(NS3BaseNode.get_rtype()) + + if not nodes: + msg = "Ipv4L3Protocol not connected to node" + self.error(msg) + raise RuntimeError, msg + + return nodes[0] +
    + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.simulation) + return rms + + def _configure_object(self): + simulation = self.simulation + + self.list_routing_uuid = simulation.create("Ipv4ListRouting") + simulation.invoke(self.uuid, "SetRoutingProtocol", self.list_routing_uuid) + + self.static_routing_uuid = simulation.create("Ipv4StaticRouting") + simulation.invoke(self.list_routing_uuid, "AddRoutingProtocol", + self.static_routing_uuid, 0) + + self.global_routing_uuid = simulation.create("Ipv4GlobalRouting") + simulation.invoke(self.list_routing_uuid, "AddRoutingProtocol", + self.global_routing_uuid, -10) + + def _connect_object(self): + pass
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3mobilitymodel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3mobilitymodel.html new file mode 100644 index 00000000..63b72b4b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3mobilitymodel.html @@ -0,0 +1,135 @@ + + + + + + + + nepi.resources.ns3.ns3mobilitymodel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3mobilitymodel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +# TODO: 
    +#       - mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
    +#       - set hook for Position - SetPosition(Vector)
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseMobilityModel(NS3Base): + _rtype = "abstract::ns3::MobilityModel" + + def _configure_object(self): + # Set initial position + position = self.get("Position") + if position: + self.simulation.ns3_set(self.uuid, "Position", position) + + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.simulation) + return rms + + def _connect_object(self): + pass
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3netdevice.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3netdevice.html new file mode 100644 index 00000000..51630fad --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3netdevice.html @@ -0,0 +1,313 @@ + + + + + + + + nepi.resources.ns3.ns3netdevice — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3netdevice

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags
    +from nepi.execution.resource import clsinit_copy
    +from nepi.execution.trace import Trace
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +import ipaddr
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseNetDevice(NS3Base): + _rtype = "abstract::ns3::NetDevice" + + @classmethod + def _register_attributes(cls): + mac = Attribute("mac", "MAC address for device", + flags = Flags.Design) + + ip = Attribute("ip", "IP address for device", + flags = Flags.Design) + + prefix = Attribute("prefix", "Network prefix for device", + flags = Flags.Design) + + cls._register_attribute(mac) + cls._register_attribute(ip) + cls._register_attribute(prefix) + + @classmethod + def _register_traces(cls): + pcap = Trace("pcap", "Dump traffic sniffed on the network device in Pcap format") + promisc_pcap = Trace("promiscPcap", "Dump traffic sniffed in promiscuous mode on the network device in Pcap format") + ascii = Trace("ascii", "Dump traffic sniffed on the network device in Ascii format") + + cls._register_trace(pcap) + cls._register_trace(promisc_pcap) + cls._register_trace(ascii) + + def __init__(self, ec, guid): + super(NS3BaseNetDevice, self).__init__(ec, guid) + self._ascii_helper_uuid = None + self._device_helper_uuid = None + + @property +
    [docs] def node(self): + from nepi.resources.ns3.ns3node import NS3BaseNode + nodes = self.get_connected(NS3BaseNode.get_rtype()) + + if not nodes: + msg = "Device not connected to node" + self.error(msg) + raise RuntimeError, msg + + return nodes[0] +
    + @property +
    [docs] def channel(self): + from nepi.resources.ns3.ns3channel import NS3BaseChannel + channels = self.get_connected(NS3BaseChannel.get_rtype()) + + if not channels: + msg = "Device not connected to channel" + self.error(msg) + raise RuntimeError, msg + + return channels[0] +
    + @property +
    [docs] def queue(self): + from nepi.resources.ns3.ns3queue import NS3BaseQueue + queue = self.get_connected(NS3BaseQueue.get_rtype()) + + if not queue: + msg = "Device not connected to queue" + self.error(msg) + raise RuntimeError, msg + + return queue[0] +
    + @property +
    [docs] def ascii_helper_uuid(self): + if not self._ascii_helper_uuid: + self._ascii_helper_uuid = self.simulation.create("AsciiTraceHelper") + return self._ascii_helper_uuid +
    + @property +
    [docs] def device_helper_uuid(self): + if not self._device_helper_uuid: + rtype = self.get_rtype() + if rtype == "ns3::PointToPointNetDevice": + classname = "PointToPointHelper" + elif rtype == "ns3::CsmaNetDevice": + classname = "CsmaHelper" + elif rtype == "ns3::EmuNetDevice": + classname = "EmuHelper" + elif rtype == "ns3::FdNetDevice": + classname = "FdNetDeviceHelper" + elif rtype in [ "ns3::BaseStationNetDevice", "SubscriberStationNetDevice" ]: + classname = "WimaxHelper" + elif rtype == "ns3::WifiNetDevice": + classname = "YansWifiPhyHelper" + elif rtype == "ns3::FdNetDevice": + classname = "FdNetDeviceHelper" + + self._device_helper_uuid = self.simulation.create(classname) + + return self._device_helper_uuid +
    + @property + def _rms_to_wait(self): + rms = set([self.node, self.channel]) + return rms + + def _configure_object(self): + # Set Mac + self._configure_mac_address() + + # Set IP address + self._configure_ip_address() + + # Enable traces + self._configure_traces() + + def _configure_mac_address(self): + mac = self.get("mac") + if mac: + mac_uuid = self.simulation.create("Mac48Address", mac) + else: + mac_uuid = self.simulation.invoke("singleton::Mac48Address", "Allocate") + + self.simulation.invoke(self.uuid, "SetAddress", mac_uuid) + + def _configure_ip_address(self): + ip = self.get("ip") + prefix = self.get("prefix") + + i = ipaddr.IPAddress(ip) + if i.version == 4: + # IPv4 + ipv4 = self.node.ipv4 + ifindex_uuid = self.simulation.invoke(ipv4.uuid, "AddInterface", + self.uuid) + ipv4_addr_uuid = self.simulation.create("Ipv4Address", ip) + ipv4_mask_uuid = self.simulation.create("Ipv4Mask", "/%s" % str(prefix)) + inaddr_uuid = self.simulation.create("Ipv4InterfaceAddress", + ipv4_addr_uuid, ipv4_mask_uuid) + self.simulation.invoke(ipv4.uuid, "AddAddress", ifindex_uuid, + inaddr_uuid) + self.simulation.invoke(ipv4.uuid, "SetMetric", ifindex_uuid, 1) + self.simulation.invoke(ipv4.uuid, "SetUp", ifindex_uuid) + else: + # IPv6 + # TODO! + pass + + def _configure_traces(self): + if self.trace_enabled("pcap"): + helper_uuid = self.device_helper_uuid + + filename = "trace-pcap-netdev-%d.pcap" % self.guid + self._trace_filename["pcap"] = filename + + filepath = self.simulation.trace_filepath(filename) + + self.simulation.invoke(helper_uuid, "EnablePcap", filepath, + self.uuid, promiscuous = False, explicitFilename = True) + + if self.trace_enabled("promiscPcap"): + helper_uuid = self.device_helper_uuid + + filename = "trace-promisc-pcap-netdev-%d.pcap" % self.guid + self._trace_filename["promiscPcap"] = filename + + filepath = self.simulation.trace_filepath(filename) + + self.simulation.invoke(helper_uuid, "EnablePcap", filepath, + self.uuid, promiscuous = True, explicitFilename = True) + + if self.trace_enabled("ascii"): + helper_uuid = self.device_helper_uuid + ascii_helper_uuid = self.ascii_helper_uuid + + filename = "trace-ascii-netdev-%d.tr" % self.guid + self._trace_filename["ascii"] = filename + + filepath = self.simulation.trace_filepath(filename) + stream_uuid = self.simulation.invoke(ascii_helper_uuid, + "CreateFileStream", filepath) + self.simulation.invoke(helper_uuid, "EnableAscii", stream_uuid, + self.uuid) + + def _connect_object(self): + node = self.node + if node and node.uuid not in self.connected: + self.simulation.invoke(node.uuid, "AddDevice", self.uuid) + self._connected.add(node.uuid) + + channel = self.channel + if channel and channel.uuid not in self.connected: + self.simulation.invoke(self.uuid, "Attach", channel.uuid) + self._connected.add(channel.uuid) + + # Verify that the device has a queue. If no queue is added a segfault + # error occurs + queue = self.queue +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3node.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3node.html new file mode 100644 index 00000000..af6fefa7 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3node.html @@ -0,0 +1,285 @@ + + + + + + + + nepi.resources.ns3.ns3node — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3node

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseNode(NS3Base): + _rtype = "abstract::ns3::Node" + + def __init__(self, ec, guid): + super(NS3BaseNode, self).__init__(ec, guid) + self._simulation = None + self._node_id = None + self._ipv4 = None + self._arp = None + self._mobility = None + self._devices = None + self._dceapplications = None + + @classmethod + def _register_attributes(cls): + enablestack = Attribute("enableStack", + "Install network stack in Node, including: ARP, " + "IP4, ICMP, UDP and TCP ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + cls._register_attribute(enablestack) + + @property +
    [docs] def simulation(self): + if not self._simulation: + from nepi.resources.ns3.ns3simulation import NS3Simulation + for guid in self.connections: + rm = self.ec.get_resource(guid) + if isinstance(rm, NS3Simulation): + self._simulation = rm + + if not self._simulation: + msg = "Node not connected to simulation" + self.error(msg) + raise RuntimeError, msg + + return self._simulation +
    + @property +
    [docs] def ipv4(self): + if not self._ipv4: + from nepi.resources.ns3.ns3ipv4l3protocol import NS3BaseIpv4L3Protocol + ipv4s = self.get_connected(NS3BaseIpv4L3Protocol.get_rtype()) + if ipv4s: + self._ipv4 = ipv4s[0] + + return self._ipv4 +
    + @property +
    [docs] def arp(self): + if not self._arp: + from nepi.resources.ns3.ns3arpl3protocol import NS3BaseArpL3Protocol + arps = self.get_connected(NS3BaseArpL3Protocol.get_rtype()) + if arps: + self._arp = arps[0] + + return self._arp +
    + @property +
    [docs] def mobility(self): + if not self._mobility: + from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel + mobility = self.get_connected(NS3BaseMobilityModel.get_rtype()) + if mobility: + self._mobility = mobility[0] + + return self._mobility +
    + @property +
    [docs] def devices(self): + if not self._devices: + from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice + devices = self.get_connected(NS3BaseNetDevice.get_rtype()) + + if not devices: + msg = "Node not connected to devices" + self.error(msg) + raise RuntimeError, msg + + self._devices = devices + + return self._devices +
    + @property +
    [docs] def node_id(self): + return self._node_id +
    + @property +
    [docs] def dceapplications(self): + if not self._dceapplications: + from nepi.resources.ns3.ns3dceapplication import NS3BaseDceApplication + self._dceapplications = self.get_connected(NS3BaseDceApplication.get_rtype()) + + return self._dceapplications +
    + @property + def _rms_to_wait(self): + rms = set([self.simulation]) + + if self.ipv4: + rms.add(self.ipv4) + + if self.arp: + rms.add(self.arp) + + if self.mobility: + rms.add(self.mobility) + + return rms + + def _configure_object(self): + if self.get("enableStack"): + uuid_stack_helper = self.simulation.create("InternetStackHelper") + self.simulation.invoke(uuid_stack_helper, "Install", self.uuid) + + # Retrieve IPV4 object + ipv4_uuid = self.simulation.invoke(self.uuid, "retrieveObject", + "ns3::Ipv4L3Protocol") + + # Add IPv4 RM to the node + ipv4 = self.ec.register_resource("ns3::Ipv4L3Protocol") + self.ec.register_connection(self.guid, ipv4) + ipv4rm = self.ec.get_resource(ipv4) + ipv4rm._uuid = ipv4_uuid + ipv4rm.set_started() + else: + ### node.AggregateObject(PacketSocketFactory()) + uuid_packet_socket_factory = self.simulation.create("PacketSocketFactory") + self.simulation.invoke(self.uuid, "AggregateObject", uuid_packet_socket_factory) + + self._node_id = self.simulation.invoke(self.uuid, "GetId") + + dceapplications = self.dceapplications + if dceapplications: + self._add_dce(dceapplications) + + def _connect_object(self): + if not self.get("enableStack"): + ipv4 = self.ipv4 + if ipv4: + self.simulation.invoke(self.uuid, "AggregateObject", ipv4.uuid) + self._connected.add(ipv4.uuid) + ipv4._connected.add(self.uuid) + + arp = self.arp + if arp: + self.simulation.invoke(self.uuid, "AggregateObject", arp.uuid) + self._connected.add(arp.uuid) + arp._connected.add(self.uuid) + + mobility = self.mobility + if mobility: + self.simulation.invoke(self.uuid, "AggregateObject", mobility.uuid) + self._connected.add(mobility.uuid) + mobility._connected.add(self.uuid) + + def _add_dce(self, dceapplications): + dceapp = dceapplications[0] + + container_uuid = self.simulation.create("NodeContainer") + self.simulation.invoke(container_uuid, "Add", self.uuid) + + dce_helper = self.simulation.dce_helper + + with dce_helper.dce_manager_lock: + dce_manager_uuid = dce_helper.dce_manager_uuid + + self.simulation.invoke(dce_manager_uuid, "Install", container_uuid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3pipechanel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3pipechanel.html new file mode 100644 index 00000000..6ebc43de --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3pipechanel.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.ns3pipechanel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3pipechanel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +import socket
    +
    +@clsinit_copy
    +
    [docs]class NS3BasePipeChannel(NS3Base): + """ Interconnects two FdNetDevices with a PIPE + """ + _rtype = "ns3::PipeChannel" + + def __init__(self, ec, guid): + super(NS3BasePipeChannel, self).__init__(ec, guid) + self._devices = None + + @property +
    [docs] def devices(self): + if not self._devices: + from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice + devices = self.get_connected(NS3BaseFdNetDevice.get_rtype()) + if not devices or len(devices) != 2: + msg = "PipeChannel must be connected to exactly to two FdNetDevices" + self.error(msg) + raise RuntimeError, msg + + self._devices = devices + + return self._devices +
    + @property +
    [docs] def node(self): + return self.devices[0].node +
    + @property + def _rms_to_wait(self): + rms = set(self.devices) + return rms + + def _instantiate_object(self): + """ The pipe channel does not really exists as an ns-3 object. + Do nothing. + """ + pass + + def _connect_object(self): + dev1 = self.devices[0] + dev2 = self.devices[1] + + if dev1.uuid not in self.connected and dev2.uuid not in self.connected: + (s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) + + dev1.send_fd(s0) + + self._connected.add(dev1.uuid) + dev1._connected.add(self.uuid) + + dev2.send_fd(s1) + + self._connected.add(dev2.uuid) + dev2._connected.add(self.uuid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationdelaymodel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationdelaymodel.html new file mode 100644 index 00000000..885465e0 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationdelaymodel.html @@ -0,0 +1,144 @@ + + + + + + + + nepi.resources.ns3.ns3propagationdelaymodel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3propagationdelaymodel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3BasePropagationDelayModel(NS3Base): + _rtype = "abstract::ns3::PropagationDelayModel" + + @property +
    [docs] def simulation(self): + return self.channel.simulation +
    + @property +
    [docs] def channel(self): + from nepi.resources.ns3.ns3wifichannel import NS3BaseWifiChannel + channels = self.get_connected(NS3BaseWifiChannel.get_rtype()) + + if not channels: + msg = "PropagationDelayModel not connected to channel" + self.error(msg) + raise RuntimeError, msg + + return channels[0] +
    + @property + def _rms_to_wait(self): + others = set() + others.add(self.channel) + return others + + def _connect_object(self): + channel = self.channel + if channel.uuid not in self.connected: + self.simulation.invoke(channel.uuid, "SetPropagationDelayModel", self.uuid) + self._connected.add(channel.uuid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationlossmodel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationlossmodel.html new file mode 100644 index 00000000..8ded8355 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationlossmodel.html @@ -0,0 +1,144 @@ + + + + + + + + nepi.resources.ns3.ns3propagationlossmodel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3propagationlossmodel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3BasePropagationLossModel(NS3Base): + _rtype = "ns3::PropagationLossModel" + + @property +
    [docs] def simulation(self): + return self.channel.simulation +
    + @property +
    [docs] def channel(self): + from nepi.resources.ns3.ns3wifichannel import NS3BaseWifiChannel + channels = self.get_connected(NS3BaseWifiChannel.get_rtype()) + + if not channels: + msg = "PropagationLossModel not connected to channel" + self.error(msg) + raise RuntimeError, msg + + return channels[0] +
    + @property + def _rms_to_wait(self): + others = set() + others.add(self.channel) + return others + + def _connect_object(self): + channel = self.channel + if channel.uuid not in self.connected: + self.simulation.invoke(channel.uuid, "SetPropagationLossModel", self.uuid) + self._connected.add(channel.uuid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3queue.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3queue.html new file mode 100644 index 00000000..b61b1174 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3queue.html @@ -0,0 +1,145 @@ + + + + + + + + nepi.resources.ns3.ns3queue — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3queue

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseQueue(NS3Base): + _rtype = "abstract::ns3::Queue" + + @property +
    [docs] def device(self): + from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice + devices = self.get_connected(NS3BaseNetDevice.get_rtype()) + + if not devices: + msg = "Queue not connected to device" + self.error(msg, out, err) + raise RuntimeError, msg + + return devices[0] +
    + @property +
    [docs] def node(self): + return self.device.node +
    + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.device) + return rms + + def _connect_object(self): + device = self.device + if device.uuid not in self.connected: + self.simulation.invoke(device.uuid, "SetQueue", self.uuid) + self._connected.add(device.uuid) + device._connected.add(self.uuid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3route.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3route.html new file mode 100644 index 00000000..0364fb10 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3route.html @@ -0,0 +1,183 @@ + + + + + + + + nepi.resources.ns3.ns3route — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3route

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags
    +from nepi.execution.resource import clsinit_copy
    +from nepi.execution.trace import Trace
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +import ipaddr
    +
    +@clsinit_copy
    +
    [docs]class NS3Route(NS3Base): + _rtype = "ns3::Route" + + @classmethod + def _register_attributes(cls): + network = Attribute("network", "Destination network address", + flags = Flags.Design) + + prefix = Attribute("prefix", "Network prefix for the network", + flags = Flags.Design) + + nexthop = Attribute("nexthop", "Address of next hop in the route", + flags = Flags.Design) + + cls._register_attribute(network) + cls._register_attribute(prefix) + cls._register_attribute(nexthop) + + def __init__(self, ec, guid): + super(NS3Route, self).__init__(ec, guid) + + @property +
    [docs] def node(self): + from nepi.resources.ns3.ns3node import NS3BaseNode + nodes = self.get_connected(NS3BaseNode.get_rtype()) + + if not nodes: + msg = "Device not connected to node" + self.error(msg) + raise RuntimeError, msg + + return nodes[0] +
    + @property + def _rms_to_wait(self): + # Wait for all network devices connected to the node to be ready + # before configuring the routes, else the route might refer to a + # non yet existing interface + + rms = set() + rms.update(self.node.devices) + return rms + + def _instantiate_object(self): + pass + + def _configure_object(self): + network = self.get("network") + prefix = self.get("prefix") + nexthop = self.get("nexthop") + ipv4_uuid = self.node.ipv4.uuid + + ret = self.simulation.invoke(ipv4_uuid, "addStaticRoute", network, + prefix, nexthop) + + if not ret: + msg = "Could not configure route %s/%s hop: %s" % (network, prefix, + nexthop) + self.error(msg) + raise RuntimeError, msg + + def _connect_object(self): + node = self.node + if node and node.uuid not in self.connected: + self._connected.add(node.uuid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3server.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3server.html new file mode 100644 index 00000000..bd8e1598 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3server.html @@ -0,0 +1,349 @@ + + + + + + + + nepi.resources.ns3.ns3server — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3server

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import base64
    +import cPickle
    +import errno
    +import logging
    +import os
    +import socket
    +import sys
    +
    +from optparse import OptionParser, SUPPRESS_HELP
    +
    +from ns3wrapper import NS3Wrapper
    +
    +
    [docs]class NS3WrapperMessage: + CREATE = "CREATE" + FACTORY = "FACTORY" + INVOKE = "INVOKE" + SET = "SET" + GET = "GET" + FLUSH = "FLUSH" + START = "START" + STOP = "STOP" + SHUTDOWN = "SHUTDOWN" +
    +
    [docs]def handle_message(ns3_wrapper, msg_type, args, kwargs): + if msg_type == NS3WrapperMessage.SHUTDOWN: + ns3_wrapper.shutdown() + + return "BYEBYE" + + if msg_type == NS3WrapperMessage.STOP: + time = kwargs.get("time") + + ns3_wrapper.stop(time=time) + + return "STOPPED" + + if msg_type == NS3WrapperMessage.START: + ns3_wrapper.start() + + return "STARTED" + + if msg_type == NS3WrapperMessage.CREATE: + clazzname = args.pop(0) + + return ns3_wrapper.create(clazzname, *args) + + if msg_type == NS3WrapperMessage.FACTORY: + type_name = args.pop(0) + + return ns3_wrapper.factory(type_name, **kwargs) + + if msg_type == NS3WrapperMessage.INVOKE: + uuid = args.pop(0) + operation = args.pop(0) + + return ns3_wrapper.invoke(uuid, operation, *args, **kwargs) + + if msg_type == NS3WrapperMessage.GET: + uuid = args.pop(0) + name = args.pop(0) + + return ns3_wrapper.get(uuid, name) + + if msg_type == NS3WrapperMessage.SET: + uuid = args.pop(0) + name = args.pop(0) + value = args.pop(0) + + return ns3_wrapper.set(uuid, name, value) + + if msg_type == NS3WrapperMessage.FLUSH: + # Forces flushing output and error streams. + # NS-3 output will stay unflushed until the program exits or + # explicit invocation flush is done + sys.stdout.flush() + sys.stderr.flush() + + ns3_wrapper.logger.debug("FLUSHED") + + return "FLUSHED" +
    +
    [docs]def open_socket(socket_name): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind(socket_name) + return sock +
    +
    [docs]def close_socket(sock): + try: + sock.close() + except: + pass +
    +
    [docs]def recv_msg(conn): + msg = [] + chunk = '' + + while '\n' not in chunk: + try: + chunk = conn.recv(1024) + except (OSError, socket.error), e: + if e[0] != errno.EINTR: + raise + # Ignore eintr errors + continue + + if chunk: + msg.append(chunk) + else: + # empty chunk = EOF + break + + msg = ''.join(msg).strip() + + # The message is formatted as follows: + # MESSAGE_TYPE|args|kwargs + # + # where MESSAGE_TYPE, args and kwargs are pickld and enoded in base64 + + def decode(item): + item = base64.b64decode(item).rstrip() + return cPickle.loads(item) + + decoded = map(decode, msg.split("|")) + + # decoded message + dmsg_type = decoded.pop(0) + dargs = list(decoded.pop(0)) # transforming touple into list + dkwargs = decoded.pop(0) + + return (dmsg_type, dargs, dkwargs) +
    +
    [docs]def send_reply(conn, reply): + encoded = base64.b64encode(cPickle.dumps(reply)) + conn.send("%s\n" % encoded) +
    +
    [docs]def get_options(): + usage = ("usage: %prog -S <socket-name> -L <ns-log> -D <enable-dump> -v ") + + parser = OptionParser(usage = usage) + + parser.add_option("-S", "--socket-name", dest="socket_name", + help = "Name for the unix socket used to interact with this process", + default = "tap.sock", type="str") + + parser.add_option("-L", "--ns-log", dest="ns_log", + help = "NS_LOG environmental variable to be set", + default = "", type="str") + + parser.add_option("-D", "--enable-dump", dest="enable_dump", + help = "Enable dumping the remote executed ns-3 commands to a script " + "in order to later reproduce and debug the experiment", + action = "store_true", + default = False) + + parser.add_option("-v", "--verbose", + help="Print debug output", + action="store_true", + dest="verbose", default=False) + + (options, args) = parser.parse_args() + + return (options.socket_name, options.verbose, options.ns_log, + options.enable_dump) +
    +
    [docs]def run_server(socket_name, level = logging.INFO, ns_log = None, + enable_dump = False): + + # Sets NS_LOG environmental variable for NS debugging + if ns_log: + os.environ["NS_LOG"] = ns_log + + ###### ns-3 wrapper instantiation + + ns3_wrapper = NS3Wrapper(loglevel=level, enable_dump = enable_dump) + + ns3_wrapper.logger.info("STARTING...") + + # create unix socket to receive instructions + sock = open_socket(socket_name) + sock.listen(0) + + # wait for messages to arrive and process them + stop = False + + while not stop: + conn, addr = sock.accept() + conn.settimeout(30) + + try: + (msg_type, args, kwargs) = recv_msg(conn) + except socket.timeout, e: + # Ingore time-out + close_socket(conn) + continue + + if not msg_type: + # Ignore - connection lost + close_socket(conn) + continue + + if msg_type == NS3WrapperMessage.SHUTDOWN: + stop = True + + try: + reply = handle_message(ns3_wrapper, msg_type, args, kwargs) + except: + import traceback + err = traceback.format_exc() + ns3_wrapper.logger.error(err) + close_socket(conn) + raise + + try: + send_reply(conn, reply) + except socket.error: + import traceback + err = traceback.format_exc() + ns3_wrapper.logger.error(err) + close_socket(conn) + raise + + close_socket(conn) + + close_socket(sock) + + ns3_wrapper.logger.info("EXITING...") +
    +if __name__ == '__main__': + + (socket_name, verbose, ns_log, enable_dump) = get_options() + + ## configure logging + FORMAT = "%(asctime)s %(name)s %(levelname)-4s %(message)s" + level = logging.DEBUG if verbose else logging.INFO + + logging.basicConfig(format = FORMAT, level = level) + + ## Run the server + run_server(socket_name, level, ns_log, enable_dump) +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3simulation.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3simulation.html new file mode 100644 index 00000000..49eaeec5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3simulation.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.ns3simulation — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3simulation

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +
    [docs]class NS3Simulation(object): + @property +
    [docs] def client(self): + return self._client +
    +
    [docs] def create(self, *args, **kwargs): + return self.client.create(*args, **kwargs) +
    +
    [docs] def factory(self, *args, **kwargs): + return self.client.factory(*args, **kwargs) +
    +
    [docs] def invoke(self, *args, **kwargs): + return self.client.invoke(*args, **kwargs) +
    +
    [docs] def ns3_set(self, *args, **kwargs): + return self.client.set(*args, **kwargs) +
    +
    [docs] def ns3_get(self, *args, **kwargs): + return self.client.get(*args, **kwargs) +
    +
    [docs] def flush(self, *args, **kwargs): + return self.client.flush(*args, **kwargs) +
    +
    [docs] def start(self, *args, **kwargs): + return self.client.start(*args, **kwargs) +
    +
    [docs] def stop(self, *args, **kwargs): + return self.client.stop(*args, **kwargs) +
    +
    [docs] def shutdown(self, *args, **kwargs): + return self.client.shutdown(*args, **kwargs) +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifichannel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifichannel.html new file mode 100644 index 00000000..48b899fa --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifichannel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.ns3wifichannel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3wifichannel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseWifiChannel(NS3Base): + _rtype = "abstract::ns3::WifiChannel" + + @property +
    [docs] def simulation(self): + return self.phys[0].device.node.simulation +
    + @property +
    [docs] def phys(self): + from nepi.resources.ns3.ns3wifiphy import NS3BaseWifiPhy + phys = self.get_connected(NS3BaseWifiPhy.get_rtype()) + + if not phys: + msg = "Channel not connected to phy" + self.error(msg) + raise RuntimeError, msg + + return phys +
    + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.simulation) + return rms + + def _connect_object(self): + pass +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifimac.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifimac.html new file mode 100644 index 00000000..3cc758e8 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifimac.html @@ -0,0 +1,169 @@ + + + + + + + + nepi.resources.ns3.ns3wifimac — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3wifimac

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +from nepi.resources.ns3.ns3wifinetdevice import WIFI_STANDARDS
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseWifiMac(NS3Base): + _rtype = "abstract::ns3::WifiMac" + + @classmethod + def _register_attributes(cls): + standard = Attribute("Standard", "Wireless standard", + default = "WIFI_PHY_STANDARD_80211a", + allowed = WIFI_STANDARDS.keys(), + type = Types.Enumerate, + flags = Flags.Design) + + cls._register_attribute(standard) + + @property +
    [docs] def node(self): + return self.device.node +
    + @property +
    [docs] def device(self): + from nepi.resources.ns3.ns3wifinetdevice import NS3BaseWifiNetDevice + devices = self.get_connected(NS3BaseWifiNetDevice.get_rtype()) + + if not devices: + msg = "WifiMac not connected to device" + self.error(msg) + raise RuntimeError, msg + + return devices[0] +
    + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.device) + return rms + + def _connect_object(self): + device = self.device + if device.uuid not in self.connected: + self._connected.add(device.uuid) + + self.simulation.invoke(device.uuid, "SetMac", self.uuid) + + standard = self.get("Standard") + self.simulation.invoke(self.uuid, "ConfigureStandard", WIFI_STANDARDS[standard]) + + # Delayed configuration of MAC address + mac = device.get("mac") + if mac: + mac_uuid = self.simulation.create("Mac48Address", mac) + else: + mac_uuid = self.simulation.invoke("singleton::Mac48Address", "Allocate") + + self.simulation.invoke(self.uuid, "SetAddress", mac_uuid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifinetdevice.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifinetdevice.html new file mode 100644 index 00000000..9dc4d7c4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifinetdevice.html @@ -0,0 +1,144 @@ + + + + + + + + nepi.resources.ns3.ns3wifinetdevice — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3wifinetdevice

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice
    +
    +WIFI_STANDARDS = dict({
    +    "WIFI_PHY_STANDARD_holland": 5,
    +    "WIFI_PHY_STANDARD_80211p_SCH": 7,
    +    "WIFI_PHY_STANDARD_80211_5Mhz": 4,
    +    "WIFI_PHY_UNKNOWN": 8,
    +    "WIFI_PHY_STANDARD_80211_10Mhz": 3,
    +    "WIFI_PHY_STANDARD_80211g": 2,
    +    "WIFI_PHY_STANDARD_80211p_CCH": 6,
    +    "WIFI_PHY_STANDARD_80211a": 0,
    +    "WIFI_PHY_STANDARD_80211b": 1
    +})
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseWifiNetDevice(NS3BaseNetDevice): + _rtype = "abstract::ns3::WifiNetDevice" + + @property + def _rms_to_wait(self): + rms = set([self.node]) + return rms + + def _configure_mac_address(self): + # The wifimac is the one responsible for + # configuring the MAC address + pass + + def _connect_object(self): + node = self.node + if node and node.uuid not in self.connected: + self.simulation.invoke(node.uuid, "AddDevice", self.uuid) + self._connected.add(node.uuid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiphy.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiphy.html new file mode 100644 index 00000000..acff23b2 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiphy.html @@ -0,0 +1,178 @@ + + + + + + + + nepi.resources.ns3.ns3wifiphy — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3wifiphy

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +from nepi.resources.ns3.ns3wifinetdevice import WIFI_STANDARDS
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseWifiPhy(NS3Base): + _rtype = "abstract::ns3::WifiPhy" + + @classmethod + def _register_attributes(cls): + standard = Attribute("Standard", "Wireless standard", + default = "WIFI_PHY_STANDARD_80211a", + allowed = WIFI_STANDARDS.keys(), + type = Types.Enumerate, + flags = Flags.Design) + + cls._register_attribute(standard) + + @property +
    [docs] def node(self): + return self.device.node +
    + @property +
    [docs] def device(self): + from nepi.resources.ns3.ns3wifinetdevice import NS3BaseWifiNetDevice + devices = self.get_connected(NS3BaseWifiNetDevice.get_rtype()) + + if not devices: + msg = "WifiPhy not connected to device" + self.error(msg) + raise RuntimeError, msg + + return devices[0] +
    + @property +
    [docs] def channel(self): + from nepi.resources.ns3.ns3wifichannel import NS3BaseWifiChannel + channels = self.get_connected(NS3BaseWifiChannel.get_rtype()) + + if not channels: + msg = "WifiPhy not connected to channel" + self.error(msg) + raise RuntimeError, msg + + return channels[0] +
    + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.device) + return rms + + def _connect_object(self): + device = self.device + if device.uuid not in self.connected: + self._connected.add(device.uuid) + + self.simulation.invoke(self.uuid, "SetMobility", self.node.uuid) + + standard = self.get("Standard") + self.simulation.invoke(self.uuid, "ConfigureStandard", WIFI_STANDARDS[standard]) + + self.simulation.invoke(self.uuid, "SetDevice", device.uuid) + + self.simulation.invoke(self.uuid, "SetChannel", self.channel.uuid) + + self.simulation.invoke(device.uuid, "SetPhy", self.uuid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiremotestationmanager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiremotestationmanager.html new file mode 100644 index 00000000..edb85a3f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiremotestationmanager.html @@ -0,0 +1,145 @@ + + + + + + + + nepi.resources.ns3.ns3wifiremotestationmanager — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3wifiremotestationmanager

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.ns3.ns3base import NS3Base
    +from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice
    +
    +@clsinit_copy
    +
    [docs]class NS3BaseWifiRemoteStationManager(NS3Base): + _rtype = "abstract::ns3::WifiRemoteStationManager" + + @property +
    [docs] def node(self): + return self.device.node +
    + @property +
    [docs] def device(self): + from nepi.resources.ns3.ns3wifinetdevice import NS3BaseWifiNetDevice + devices = self.get_connected(NS3BaseWifiNetDevice.get_rtype()) + + if not devices: + msg = "WifiRemoteStationManager not connected to device" + self.error(msg) + raise RuntimeError, msg + + return devices[0] +
    + @property + def _rms_to_wait(self): + rms = set() + rms.add(self.device) + return rms + + def _connect_object(self): + device = self.device + if device.uuid not in self.connected: + self.simulation.invoke(device.uuid, "SetRemoteStationManager", self.uuid) + self._connected.add(device.uuid) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper.html new file mode 100644 index 00000000..6a5723b3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper.html @@ -0,0 +1,795 @@ + + + + + + + + nepi.resources.ns3.ns3wrapper — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3wrapper

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import logging
    +import os
    +import sys
    +import threading
    +import time
    +import uuid
    +
    +SINGLETON = "singleton::"
    +SIMULATOR_UUID = "singleton::Simulator"
    +CONFIG_UUID = "singleton::Config"
    +GLOBAL_VALUE_UUID = "singleton::GlobalValue"
    +IPV4_GLOBAL_ROUTING_HELPER_UUID = "singleton::Ipv4GlobalRoutingHelper"
    +
    +
    [docs]def load_ns3_libraries(): + import ctypes + import re + + libdir = os.environ.get("NS3LIBRARIES") + + # Load the ns-3 modules shared libraries + if libdir: + files = os.listdir(libdir) + regex = re.compile("(.*\.so)$") + libs = [m.group(1) for filename in files for m in [regex.search(filename)] if m] + + initial_size = len(libs) + # Try to load the libraries in the right order by trial and error. + # Loop until all libraries are loaded. + while len(libs) > 0: + for lib in libs: + libfile = os.path.join(libdir, lib) + try: + ctypes.CDLL(libfile, ctypes.RTLD_GLOBAL) + libs.remove(lib) + except: + #import traceback + #err = traceback.format_exc() + #print err + pass + + # if did not load any libraries in the last iteration break + # to prevent infinit loop + if initial_size == len(libs): + raise RuntimeError("Imposible to load shared libraries %s" % str(libs)) + initial_size = len(libs) +
    +
    [docs]def load_ns3_module(): + load_ns3_libraries() + + # import the python bindings for the ns-3 modules + bindings = os.environ.get("NS3BINDINGS") + if bindings: + sys.path.append(bindings) + + import pkgutil + import imp + import ns + + # create a Python module to add all ns3 classes + ns3mod = imp.new_module("ns3") + sys.modules["ns3"] = ns3mod + + for importer, modname, ispkg in pkgutil.iter_modules(ns.__path__): + if modname in [ "visualizer" ]: + continue + + fullmodname = "ns.%s" % modname + module = __import__(fullmodname, globals(), locals(), ['*']) + + for sattr in dir(module): + if sattr.startswith("_"): + continue + + attr = getattr(module, sattr) + + # netanim.Config and lte.Config singleton overrides ns3::Config + if sattr == "Config" and modname in ['netanim', 'lte']: + sattr = "%s.%s" % (modname, sattr) + + setattr(ns3mod, sattr, attr) + + return ns3mod +
    +
    [docs]class NS3Wrapper(object): + def __init__(self, loglevel = logging.INFO, enable_dump = False): + super(NS3Wrapper, self).__init__() + # Thread used to run the simulation + self._simulation_thread = None + self._condition = None + + # True if Simulator::Run was invoked + self._started = False + + # holds reference to all C++ objects and variables in the simulation + self._objects = dict() + + # Logging + self._logger = logging.getLogger("ns3wrapper") + self._logger.setLevel(loglevel) + + ## NOTE that the reason to create a handler to the ns3 module, + # that is re-loaded each time a ns-3 wrapper is instantiated, + # is that else each unit test for the ns3wrapper class would need + # a separate file. Several ns3wrappers would be created in the + # same unit test (single process), leading to inchorences in the + # state of ns-3 global objects + # + # Handler to ns3 classes + self._ns3 = None + + # Collection of allowed ns3 classes + self._allowed_types = None + + # Object to dump instructions to reproduce and debug experiment + from ns3wrapper_debug import NS3WrapperDebuger + self._debuger = NS3WrapperDebuger(enabled = enable_dump) + + @property +
    [docs] def debuger(self): + return self._debuger +
    + @property +
    [docs] def ns3(self): + if not self._ns3: + # load ns-3 libraries and bindings + self._ns3 = load_ns3_module() + + return self._ns3 +
    + @property +
    [docs] def allowed_types(self): + if not self._allowed_types: + self._allowed_types = set() + type_id = self.ns3.TypeId() + + tid_count = type_id.GetRegisteredN() + base = type_id.LookupByName("ns3::Object") + + for i in xrange(tid_count): + tid = type_id.GetRegistered(i) + + if tid.MustHideFromDocumentation() or \ + not tid.HasConstructor() or \ + not tid.IsChildOf(base): + continue + + type_name = tid.GetName() + self._allowed_types.add(type_name) + + return self._allowed_types +
    + @property +
    [docs] def logger(self): + return self._logger +
    + @property +
    [docs] def is_running(self): + return self.is_started and not self.ns3.Simulator.IsFinished() +
    + @property +
    [docs] def is_started(self): + if not self._started: + now = self.ns3.Simulator.Now() + if not now.IsZero(): + self._started = True + + return self._started +
    + @property +
    [docs] def is_finished(self): + return self.ns3.Simulator.IsFinished() +
    +
    [docs] def make_uuid(self): + return "uuid%s" % uuid.uuid4() +
    +
    [docs] def get_object(self, uuid): + return self._objects.get(uuid) +
    +
    [docs] def factory(self, type_name, **kwargs): + """ This method should be used to construct ns-3 objects + that have a TypeId and related introspection information """ + + if type_name not in self.allowed_types: + msg = "Type %s not supported" % (type_name) + self.logger.error(msg) + + uuid = self.make_uuid() + + ### DEBUG + self.logger.debug("FACTORY %s( %s )" % (type_name, str(kwargs))) + + ### DUMP + self.debuger.dump_factory(uuid, type_name, kwargs) + + factory = self.ns3.ObjectFactory() + factory.SetTypeId(type_name) + + for name, value in kwargs.iteritems(): + ns3_value = self._attr_from_string_to_ns3_value(type_name, name, value) + factory.Set(name, ns3_value) + + obj = factory.Create() + + self._objects[uuid] = obj + + ### DEBUG + self.logger.debug("RET FACTORY ( uuid %s ) %s = %s( %s )" % ( + str(uuid), str(obj), type_name, str(kwargs))) + + return uuid +
    +
    [docs] def create(self, clazzname, *args): + """ This method should be used to construct ns-3 objects that + do not have a TypeId (e.g. Values) """ + + if not hasattr(self.ns3, clazzname): + msg = "Type %s not supported" % (clazzname) + self.logger.error(msg) + + uuid = self.make_uuid() + + ### DEBUG + self.logger.debug("CREATE %s( %s )" % (clazzname, str(args))) + + ### DUMP + self.debuger.dump_create(uuid, clazzname, args) + + clazz = getattr(self.ns3, clazzname) + + # arguments starting with 'uuid' identify ns-3 C++ + # objects and must be replaced by the actual object + realargs = self.replace_args(args) + + obj = clazz(*realargs) + + self._objects[uuid] = obj + + ### DEBUG + self.logger.debug("RET CREATE ( uuid %s ) %s = %s( %s )" % (str(uuid), + str(obj), clazzname, str(args))) + + return uuid +
    +
    [docs] def invoke(self, uuid, operation, *args, **kwargs): + ### DEBUG + self.logger.debug("INVOKE %s -> %s( %s, %s ) " % ( + uuid, operation, str(args), str(kwargs))) + ######## + + result = None + newuuid = None + + if operation == "isRunning": + result = self.is_running + + elif operation == "isStarted": + result = self.is_started + + elif operation == "isFinished": + result = self.is_finished + + elif operation == "isAppRunning": + result = self._is_app_running(uuid) + + elif operation == "isAppStarted": + result = self._is_app_started(uuid) + + elif operation == "recvFD": + ### passFD operation binds to a different random socket + ### en every execution, so the socket name that could be + ### dumped to the debug script using dump_invoke is + ### not be valid accross debug executions. + result = self._recv_fd(uuid, *args, **kwargs) + + elif operation == "addStaticRoute": + result = self._add_static_route(uuid, *args) + + ### DUMP - result is static, so will be dumped as plain text + self.debuger.dump_invoke(result, uuid, operation, args, kwargs) + + elif operation == "retrieveObject": + result = self._retrieve_object(uuid, *args, **kwargs) + + ### DUMP - result is static, so will be dumped as plain text + self.debuger.dump_invoke(result, uuid, operation, args, kwargs) + + else: + newuuid = self.make_uuid() + + ### DUMP - result is a uuid that encoded an dynamically generated + ### object + self.debuger.dump_invoke(newuuid, uuid, operation, args, kwargs) + + if uuid.startswith(SINGLETON): + obj = self._singleton(uuid) + else: + obj = self.get_object(uuid) + + method = getattr(obj, operation) + + # arguments starting with 'uuid' identify ns-3 C++ + # objects and must be replaced by the actual object + realargs = self.replace_args(args) + realkwargs = self.replace_kwargs(kwargs) + + result = method(*realargs, **realkwargs) + + # If the result is an object (not a base value), + # then keep track of the object a return the object + # reference (newuuid) + if not (result is None or type(result) in [ + bool, float, long, str, int]): + self._objects[newuuid] = result + result = newuuid + + ### DEBUG + self.logger.debug("RET INVOKE %s%s = %s -> %s(%s, %s) " % ( + "(uuid %s) " % str(newuuid) if newuuid else "", str(result), uuid, + operation, str(args), str(kwargs))) + ######## + + return result +
    + def _set_attr(self, obj, name, ns3_value): + obj.SetAttribute(name, ns3_value) + +
    [docs] def set(self, uuid, name, value): + ### DEBUG + self.logger.debug("SET %s %s %s" % (uuid, name, str(value))) + + ### DUMP + self.debuger.dump_set(uuid, name, value) + + obj = self.get_object(uuid) + type_name = obj.GetInstanceTypeId().GetName() + ns3_value = self._attr_from_string_to_ns3_value(type_name, name, value) + + # If the Simulation thread is not running, + # then there will be no thread-safety problems + # in changing the value of an attribute directly. + # However, if the simulation is running we need + # to set the value by scheduling an event, else + # we risk to corrupt the state of the + # simulation. + + event_executed = [False] + + if self.is_running: + # schedule the event in the Simulator + self._schedule_event(self._condition, event_executed, + self._set_attr, obj, name, ns3_value) + + if not event_executed[0]: + self._set_attr(obj, name, ns3_value) + + ### DEBUG + self.logger.debug("RET SET %s = %s -> set(%s, %s)" % (str(value), uuid, name, + str(value))) + + return value +
    + def _get_attr(self, obj, name, ns3_value): + obj.GetAttribute(name, ns3_value) + +
    [docs] def get(self, uuid, name): + ### DEBUG + self.logger.debug("GET %s %s" % (uuid, name)) + + ### DUMP + self.debuger.dump_get(uuid, name) + + obj = self.get_object(uuid) + type_name = obj.GetInstanceTypeId().GetName() + ns3_value = self._create_attr_ns3_value(type_name, name) + + event_executed = [False] + + if self.is_running: + # schedule the event in the Simulator + self._schedule_event(self._condition, event_executed, + self._get_attr, obj, name, ns3_value) + + if not event_executed[0]: + self._get_attr(obj, name, ns3_value) + + result = self._attr_from_ns3_value_to_string(type_name, name, ns3_value) + + ### DEBUG + self.logger.debug("RET GET %s = %s -> get(%s)" % (str(result), uuid, name)) + + return result +
    +
    [docs] def start(self): + ### DUMP + self.debuger.dump_start() + + # Launch the simulator thread and Start the + # simulator in that thread + self._condition = threading.Condition() + self._simulator_thread = threading.Thread( + target = self._simulator_run, + args = [self._condition]) + self._simulator_thread.setDaemon(True) + self._simulator_thread.start() + + ### DEBUG + self.logger.debug("START") +
    +
    [docs] def stop(self, time = None): + ### DUMP + self.debuger.dump_stop(time=time) + + if time is None: + self.ns3.Simulator.Stop() + else: + self.ns3.Simulator.Stop(self.ns3.Time(time)) + + ### DEBUG + self.logger.debug("STOP time=%s" % str(time)) +
    +
    [docs] def shutdown(self): + ### DUMP + self.debuger.dump_shutdown() + + while not self.ns3.Simulator.IsFinished(): + #self.logger.debug("Waiting for simulation to finish") + time.sleep(0.5) + + if self._simulator_thread: + self._simulator_thread.join() + + self.ns3.Simulator.Destroy() + + # Remove all references to ns-3 objects + self._objects.clear() + + sys.stdout.flush() + sys.stderr.flush() + + ### DEBUG + self.logger.debug("SHUTDOWN") +
    + def _simulator_run(self, condition): + # Run simulation + self.ns3.Simulator.Run() + # Signal condition to indicate simulation ended and + # notify waiting threads + condition.acquire() + condition.notifyAll() + condition.release() + + def _schedule_event(self, condition, event_executed, func, *args): + """ Schedules event on running simulation, and wait until + event is executed""" + + def execute_event(contextId, condition, event_executed, func, *args): + try: + func(*args) + event_executed[0] = True + finally: + # notify condition indicating event was executed + condition.acquire() + condition.notifyAll() + condition.release() + + # contextId is defined as general context + contextId = long(0xffffffff) + + # delay 0 means that the event is expected to execute inmediately + delay = self.ns3.Seconds(0) + + # Mark event as not executed + event_executed[0] = False + + condition.acquire() + try: + self.ns3.Simulator.ScheduleWithContext(contextId, delay, execute_event, + condition, event_executed, func, *args) + if not self.ns3.Simulator.IsFinished(): + condition.wait() + finally: + condition.release() + + def _create_attr_ns3_value(self, type_name, name): + TypeId = self.ns3.TypeId() + tid = TypeId.LookupByName(type_name) + info = TypeId.AttributeInformation() + if not tid.LookupAttributeByName(name, info): + msg = "TypeId %s has no attribute %s" % (type_name, name) + self.logger.error(msg) + + checker = info.checker + ns3_value = checker.Create() + return ns3_value + + def _attr_from_ns3_value_to_string(self, type_name, name, ns3_value): + TypeId = self.ns3.TypeId() + tid = TypeId.LookupByName(type_name) + info = TypeId.AttributeInformation() + if not tid.LookupAttributeByName(name, info): + msg = "TypeId %s has no attribute %s" % (type_name, name) + self.logger.error(msg) + + checker = info.checker + value = ns3_value.SerializeToString(checker) + + type_name = checker.GetValueTypeName() + if type_name in ["ns3::UintegerValue", "ns3::IntegerValue"]: + return int(value) + if type_name == "ns3::DoubleValue": + return float(value) + if type_name == "ns3::BooleanValue": + return value == "true" + + return value + + def _attr_from_string_to_ns3_value(self, type_name, name, value): + TypeId = self.ns3.TypeId() + tid = TypeId.LookupByName(type_name) + info = TypeId.AttributeInformation() + if not tid.LookupAttributeByName(name, info): + msg = "TypeId %s has no attribute %s" % (type_name, name) + self.logger.error(msg) + + str_value = str(value) + if isinstance(value, bool): + str_value = str_value.lower() + + checker = info.checker + ns3_value = checker.Create() + ns3_value.DeserializeFromString(str_value, checker) + return ns3_value + + # singletons are identified as "ns3::ClassName" + def _singleton(self, ident): + if not ident.startswith(SINGLETON): + return None + + clazzname = ident[ident.find("::")+2:] + if not hasattr(self.ns3, clazzname): + msg = "Type %s not supported" % (clazzname) + self.logger.error(msg) + + return getattr(self.ns3, clazzname) + + # replace uuids and singleton references for the real objects +
    [docs] def replace_args(self, args): + realargs = [self.get_object(arg) if \ + str(arg).startswith("uuid") else arg for arg in args] + + realargs = [self._singleton(arg) if \ + str(arg).startswith(SINGLETON) else arg for arg in realargs] + + return realargs + + # replace uuids and singleton references for the real objects
    +
    [docs] def replace_kwargs(self, kwargs): + realkwargs = dict([(k, self.get_object(v) \ + if str(v).startswith("uuid") else v) \ + for k,v in kwargs.iteritems()]) + + realkwargs = dict([(k, self._singleton(v) \ + if str(v).startswith(SINGLETON) else v )\ + for k, v in realkwargs.iteritems()]) + + return realkwargs +
    + def _is_app_running(self, uuid): + now = self.ns3.Simulator.Now() + if now.IsZero(): + return False + + if self.ns3.Simulator.IsFinished(): + return False + + app = self.get_object(uuid) + stop_time_value = self.ns3.TimeValue() + app.GetAttribute("StopTime", stop_time_value) + stop_time = stop_time_value.Get() + + start_time_value = self.ns3.TimeValue() + app.GetAttribute("StartTime", start_time_value) + start_time = start_time_value.Get() + + if now.Compare(start_time) >= 0: + if stop_time.IsZero() or now.Compare(stop_time) < 0: + return True + + return False + + def _is_app_started(self, uuid): + return self._is_app_running(uuid) or self.is_finished + + def _add_static_route(self, ipv4_uuid, network, prefix, nexthop): + ipv4 = self.get_object(ipv4_uuid) + + list_routing = ipv4.GetRoutingProtocol() + (static_routing, priority) = list_routing.GetRoutingProtocol(0) + + ifindex = self._find_ifindex(ipv4, nexthop) + if ifindex == -1: + return False + + nexthop = self.ns3.Ipv4Address(nexthop) + + if network in ["0.0.0.0", "0", None]: + # Default route: 0.0.0.0/0 + static_routing.SetDefaultRoute(nexthop, ifindex) + else: + mask = self.ns3.Ipv4Mask("/%s" % prefix) + network = self.ns3.Ipv4Address(network) + + if prefix == 32: + # Host route: x.y.z.w/32 + static_routing.AddHostRouteTo(network, nexthop, ifindex) + else: + # Network route: x.y.z.w/n + static_routing.AddNetworkRouteTo(network, mask, nexthop, + ifindex) + return True + + def _find_ifindex(self, ipv4, nexthop): + ifindex = -1 + + nexthop = self.ns3.Ipv4Address(nexthop) + + # For all the interfaces registered with the ipv4 object, find + # the one that matches the network of the nexthop + nifaces = ipv4.GetNInterfaces() + for ifidx in xrange(nifaces): + iface = ipv4.GetInterface(ifidx) + naddress = iface.GetNAddresses() + for addridx in xrange(naddress): + ifaddr = iface.GetAddress(addridx) + ifmask = ifaddr.GetMask() + + ifindex = ipv4.GetInterfaceForPrefix(nexthop, ifmask) + + if ifindex == ifidx: + return ifindex + return ifindex + + def _retrieve_object(self, uuid, typeid, search = False): + obj = self.get_object(uuid) + + type_id = self.ns3.TypeId() + tid = type_id.LookupByName(typeid) + nobj = obj.GetObject(tid) + + newuuid = None + if search: + # search object + for ouuid, oobj in self._objects.iteritems(): + if nobj == oobj: + newuuid = ouuid + break + else: + newuuid = self.make_uuid() + self._objects[newuuid] = nobj + + return newuuid + + def _recv_fd(self, uuid): + """ Waits on a local address to receive a file descriptor + from a local process. The file descriptor is associated + to a FdNetDevice to stablish communication between the + simulation and what ever process writes on that file descriptor + """ + + def recvfd(sock, fdnd): + (fd, msg) = passfd.recvfd(sock) + # Store a reference to the endpoint to keep the socket alive + fdnd.SetFileDescriptor(fd) + + import passfd + import socket + sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) + sock.bind("") + address = sock.getsockname() + + fdnd = self.get_object(uuid) + t = threading.Thread(target=recvfd, args=(sock,fdnd)) + t.start() + + return address +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper_debug.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper_debug.html new file mode 100644 index 00000000..fe27b391 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper_debug.html @@ -0,0 +1,271 @@ + + + + + + + + nepi.resources.ns3.ns3wrapper_debug — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.ns3wrapper_debug

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +
    +############ METHODS DEBUG NS3WRAPPER EXECUTION
    +##
    +## The ns3wrapper works in ditributed mode, receiving instructions from
    +## a remote client. This makes it very hard to debug scripting errors 
    +## in the client side. To simplify error debugging, when set to debug mode,
    +## the ns3wrapper dumps every executed line to a script that can be then
    +## executed locally to reproduce and debug the experiment.
    +##
    +###########################################################################
    +
    +import logging
    +
    +SINGLETON = "singleton::"
    +
    +
    [docs]class NS3WrapperDebuger(object): + def __init__(self, enabled): + super(NS3WrapperDebuger, self).__init__() + self._enabled = enabled + self._script_path = "debug.py" + + self.dump_header() + + @property +
    [docs] def enabled(self): + return self._enabled +
    + @property +
    [docs] def script_path(self): + return self._script_path +
    +
    [docs] def dump_to_script(self, command): + f = open(self.script_path, "a") + f.write("%s" % command) + f.close() +
    +
    [docs] def dump_header(self): + if not self.enabled: + return + + header = """ +from ns3wrapper import NS3Wrapper + +wrapper = NS3Wrapper() + +""" + self.dump_to_script(header) +
    +
    [docs] def dump_factory(self, uuid, type_name, kwargs): + if not self.enabled: + return + + command = ("kwargs = %(kwargs)s\n" + "%(uuid)s = wrapper.factory(%(type_name)s, **kwargs)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "type_name": self.format_value(type_name), + "kwargs": self.format_kwargs(kwargs) + }) + + self.dump_to_script(command) +
    +
    [docs] def dump_create(self, uuid, clazzname, args): + if not self.enabled: + return + + command = ("args = %(args)s\n" + "%(uuid)s = wrapper.create(%(clazzname)s, *args)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "clazzname": self.format_value(clazzname), + "args": self.format_args(args), + }) + + self.dump_to_script(command) +
    +
    [docs] def dump_invoke(self, newuuid, uuid, operation, args, kwargs): + if not self.enabled: + return + + command = ("args = %(args)s\n" + "kwargs = %(kwargs)s\n" + "%(newuuid)s = wrapper.invoke(%(uuid)s, %(operation)s, *args, **kwargs)\n\n" + ) % dict({ + "newuuid": self.format_value(newuuid) if newuuid else "nothing", + "uuid": self.format_value(uuid), + "operation": self.format_value(operation), + "args": self.format_args(args), + "kwargs": self.format_kwargs(kwargs), + }) + + self.dump_to_script(command) +
    +
    [docs] def dump_set(self, uuid, name, value): + if not self.enabled: + return + + command = ("wrapper.set(%(uuid)s, %(name)s, %(value)s)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "name": self.format_value(name), + "value": self.format_value(value), + }) + + self.dump_to_script(command) +
    +
    [docs] def dump_get(self, uuid, name): + if not self.enabled: + return + + command = ("wrapper.get(%(uuid)s, %(name)s)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "name": self.format_value(name), + }) + + self.dump_to_script(command) +
    +
    [docs] def dump_start(self): + if not self.enabled: + return + + command = "wrapper.start()\n\n" + self.dump_to_script(command) +
    +
    [docs] def dump_stop(self, time = None): + if not self.enabled: + return + + command = ("wrapper.stop(time=%(time)s)\n\n" + ) % dict({ + "time": self.format_value(time) if time else "None", + }) + + self.dump_to_script(command) +
    +
    [docs] def dump_shutdown(self): + if not self.enabled: + return + + command = "wrapper.shutdown()\n\n" + self.dump_to_script(command) +
    +
    [docs] def format_value(self, value): + if isinstance(value, str) and value.startswith("uuid"): + return value.replace("-", "") + + import pprint + return pprint.pformat(value) +
    +
    [docs] def format_args(self, args): + fargs = map(self.format_value, args) + return "[%s]" % ",".join(fargs) +
    +
    [docs] def format_kwargs(self, kwargs): + fkwargs = map(lambda (k,w): + "%s: %s" % (self.format_value(k), self.format_value(w)), + kwargs.iteritems()) + + return "dict({%s})" % ",".join(fkwargs) +
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/resource_manager_generator.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/resource_manager_generator.html new file mode 100644 index 00000000..b47fabae --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/resource_manager_generator.html @@ -0,0 +1,330 @@ + + + + + + + + nepi.resources.ns3.resource_manager_generator — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.ns3.resource_manager_generator

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +#
    +# Instructions to automatically generate ns-3 ResourceManagers
    +# 
    +# Configure the ns-3 enviorment (e.g.):
    +#
    +#  export PYTHONPATH=~/.nepi/nepi-usr/bin/ns-3/ns-3.20/optimized/build/lib/python/site-packages
    +#  export LD_LIBRARY_PATH=~/.nepi/nepi-usr/bin/ns-3/ns-3.20/optimized/build/lib
    +#
    +# Run the RM generator:
    +#
    +#  PYTHONPATH=$PYTHONPATH:~/repos/nepi/src python src/nepi/resources/ns3/resource_manager_generator.py
    +#
    +
    +# Force the load of ns3 libraries
    +from nepi.resources.ns3.ns3wrapper import load_ns3_module
    +
    +import os
    +import re
    +
    +adapted_types = ["ns3::Node",
    +        "ns3::Icmpv4L4Protocol",
    +        "ns3::ArpL3Protocol",
    +        "ns3::Ipv4L3Protocol",
    +        "ns3::PropagationLossModel",
    +        "ns3::MobilityModel",
    +        "ns3::PropagationDelayModel",
    +        "ns3::WifiRemoteStationManager",
    +        "ns3::WifiNetDevice",
    +        "ns3::WifiChannel",
    +        "ns3::WifiPhy",
    +        "ns3::WifiMac",
    +        "ns3::ErrorModel",
    +        "ns3::ErrorRateModel",
    +        "ns3::Application", 
    +        "ns3::FdNetDevice",
    +        #"ns3::DceApplication", 
    +        "ns3::NetDevice",
    +        "ns3::Channel",
    +        "ns3::Queue"]
    +
    +base_types = ["ns3::IpL4Protocol"]
    +
    +
    [docs]def select_base_class(ns3, tid): + base_class_import = None + base_class = None + + rtype = tid.GetName() + + type_id = ns3.TypeId() + + for type_name in adapted_types: + tid_base = type_id.LookupByName(type_name) + if type_name == rtype or tid.IsChildOf(tid_base): + base_class = "NS3Base" + type_name.replace("ns3::", "") + base_module = "ns3" + type_name.replace("ns3::", "").lower() + base_class_import = "from nepi.resources.ns3.%s import %s " % ( + base_module, base_class) + return (base_class_import, base_class) + + base_class_import = "from nepi.resources.ns3.ns3base import NS3Base" + base_class = "NS3Base" + + for type_name in base_types: + tid_base = type_id.LookupByName(type_name) + if type_name == rtype or tid.IsChildOf(tid_base): + return (base_class_import, base_class) + + return (None, None) +
    +
    [docs]def create_ns3_rms(): + ns3 = load_ns3_module() + + type_id = ns3.TypeId() + + tid_count = type_id.GetRegisteredN() + base = type_id.LookupByName("ns3::Object") + + # Create a .py file using the ns-3 RM template for each ns-3 TypeId + for i in xrange(tid_count): + tid = type_id.GetRegistered(i) + + (base_class_import, base_class) = select_base_class(ns3, tid) + if not base_class: + continue + + if tid.MustHideFromDocumentation() or \ + not tid.HasConstructor() or \ + not tid.IsChildOf(base): + continue + + attributes = template_attributes(ns3, tid) + traces = template_traces(ns3, tid) + ptid = tid + while ptid.HasParent(): + ptid = ptid.GetParent() + attributes += template_attributes(ns3, ptid) + traces += template_traces(ns3, ptid) + + attributes = "\n" + attributes if attributes else "pass" + traces = "\n" + traces if traces else "pass" + + category = tid.GetGroupName() + + rtype = tid.GetName() + classname = rtype.replace("ns3::", "NS3").replace("::","") + uncamm_rtype = re.sub('([a-z])([A-Z])', r'\1-\2', rtype).lower() + short_rtype = uncamm_rtype.replace("::","-") + + d = os.path.dirname(os.path.realpath(__file__)) + ftemp = open(os.path.join(d, "templates", "resource_manager_template.txt"), "r") + template = ftemp.read() + ftemp.close() + + template = template. \ + replace("<CLASS_NAME>", classname). \ + replace("<RTYPE>", rtype). \ + replace("<ATTRIBUTES>", attributes). \ + replace("<TRACES>", traces). \ + replace("<BASE_CLASS_IMPORT>", base_class_import). \ + replace("<BASE_CLASS>", base_class). \ + replace("<SHORT-RTYPE>", short_rtype) + + fname = uncamm_rtype.replace('ns3::', ''). \ + replace('::', ''). \ + replace("-","_").lower() + ".py" + + f = open(os.path.join(d, "classes", fname), "w") + print os.path.join(d, fname) + print template + f.write(template) + f.close() +
    +
    [docs]def template_attributes(ns3, tid): + d = os.path.dirname(os.path.realpath(__file__)) + ftemp = open(os.path.join(d, "templates", "attribute_template.txt"), "r") + template = ftemp.read() + ftemp.close() + + attributes = "" + + attr_count = tid.GetAttributeN() + for i in xrange(attr_count): + attr_info = tid.GetAttribute(i) + if not attr_info.accessor.HasGetter(): + continue + + attr_flags = "Flags.Reserved" + flags = attr_info.flags + if (flags & ns3.TypeId.ATTR_CONSTRUCT) == ns3.TypeId.ATTR_CONSTRUCT: + attr_flags += " | Flags.Construct" + else: + if (flags & ns3.TypeId.ATTR_GET) != ns3.TypeId.ATTR_GET: + attr_flags += " | Flags.NoRead" + elif (flags & ns3.TypeId.ATTR_SET) != ns3.TypeId.ATTR_SET: + attr_flags += " | Flags.NoWrite" + + attr_name = attr_info.name + checker = attr_info.checker + attr_help = attr_info.help.replace('"', '\\"').replace("'", "\\'") + value = attr_info.initialValue + attr_value = value.SerializeToString(checker) + attr_allowed = "None" + attr_range = "None" + attr_type = "Types.String" + + if isinstance(value, ns3.ObjectVectorValue): + continue + elif isinstance(value, ns3.PointerValue): + continue + elif isinstance(value, ns3.WaypointValue): + continue + elif isinstance(value, ns3.BooleanValue): + attr_type = "Types.Bool" + attr_value = "True" if attr_value == "true" else "False" + elif isinstance(value, ns3.EnumValue): + attr_type = "Types.Enumerate" + allowed = checker.GetUnderlyingTypeInformation().split("|") + attr_allowed = "[%s]" % ",".join(map(lambda x: "\"%s\"" % x, allowed)) + elif isinstance(value, ns3.DoubleValue): + attr_type = "Types.Double" + # TODO: range + elif isinstance(value, ns3.UintegerValue): + attr_type = "Types.Integer" + # TODO: range + + attr_id = "attr_" + attr_name.lower().replace("-", "_") + attributes += template.replace("<ATTR_ID>", attr_id) \ + .replace("<ATTR_NAME>", attr_name) \ + .replace("<ATTR_HELP>", attr_help) \ + .replace("<ATTR_TYPE>", attr_type) \ + .replace("<ATTR_DEFAULT>", attr_value) \ + .replace("<ATTR_ALLOWED>", attr_allowed) \ + .replace("<ATTR_RANGE>", attr_range) \ + .replace("<ATTR_FLAGS>", attr_flags) + + return attributes +
    +
    [docs]def template_traces(ns3, tid): + d = os.path.dirname(os.path.realpath(__file__)) + ftemp = open(os.path.join(d, "templates", "trace_template.txt"), "r") + template = ftemp.read() + ftemp.close() + + traces = "" + + trace_count = tid.GetTraceSourceN() + for i in xrange(trace_count): + trace_info = tid.GetTraceSource(i) + trace_name = trace_info.name + trace_help = trace_info.help.replace('"', '\\"').replace("'", "\\'") + + trace_id = trace_name.lower() + traces += template.replace("<TRACE_ID>", trace_id) \ + .replace("<TRACE_NAME>", trace_name) \ + .replace("<TRACE_HELP>", trace_help) + + return traces +
    +if __name__ == "__main__": + create_ns3_rms() +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/application.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/application.html new file mode 100644 index 00000000..d5e68655 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/application.html @@ -0,0 +1,510 @@ + + + + + + + + nepi.resources.omf.application — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.application

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +import os
    +
    +from nepi.util.timefuncs import tnow
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.execution.trace import Trace, TraceAttr
    +from nepi.execution.attribute import Attribute, Flags 
    +from nepi.resources.omf.omf_resource import ResourceGateway, OMFResource
    +from nepi.resources.omf.node import OMFNode, confirmation_counter, reschedule_check
    +from nepi.resources.omf.omf_api_factory import OMFAPIFactory
    +
    +from nepi.util import sshfuncs
    +
    +@clsinit_copy
    +
    [docs]class OMFApplication(OMFResource): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + _rtype = "omf::Application" + _authorized_connections = ["omf::Node", "wilabt::sfa::Node"] + + @classmethod + def _register_attributes(cls): + """ Register the attributes of an OMF application + + """ + command = Attribute("command", "Command to execute") + env = Attribute("env", "Environnement variable of the application") + + # For OMF 5: + appid = Attribute("appid", "Name of the application") + stdin = Attribute("stdin", "Input of the application", default = "") + sources = Attribute("sources", "Sources of the application", + flags = Flags.Design) + sshuser = Attribute("sshUser", "user to connect with ssh", + flags = Flags.Design) + sshkey = Attribute("sshKey", "key to use for ssh", + flags = Flags.Design) + + cls._register_attribute(appid) + cls._register_attribute(command) + cls._register_attribute(env) + cls._register_attribute(stdin) + cls._register_attribute(sources) + cls._register_attribute(sshuser) + cls._register_attribute(sshkey) + + def __init__(self, ec, guid): + """ + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + :param creds: Credentials to communicate with the rm (XmppClient for OMF) + :type creds: dict + + """ + super(OMFApplication, self).__init__(ec, guid) + + self.set('command', "") + self.set('appid', "") + self._path= "" + self._args = "" + self.set('env', "") + + self._node = None + + self._omf_api = None + self._topic_app = None + self.create_id = None + self._create_cnt = 0 + self._start_cnt = 0 + self.release_id = None + self._release_cnt = 0 + + # For performance tests + self.begin_deploy_time = None + self.begin_start_time = None + self.begin_release_time = None + self.dperf = True + self.sperf = True + self.rperf = True + + self.add_set_hook() + + def _init_command(self): + comm = self.get('command').split(' ') + self._path= comm[0] + if len(comm)>1: + self._args = ' '.join(comm[1:]) + + @property +
    [docs] def exp_id(self): + return self.ec.exp_id +
    + @property +
    [docs] def node(self): + rm_list = self.get_connected(OMFNode.get_rtype()) + if rm_list: return rm_list[0] + return None +
    +
    [docs] def stdin_hook(self, old_value, new_value): + """ Set a hook to the stdin attribute in order to send a message at each time + the value of this parameter is changed. Used ofr OMF 5.4 only + + """ + self._omf_api.send_stdin(self.node.get('hostname'), new_value, self.get('appid')) + return new_value +
    +
    [docs] def add_set_hook(self): + """ Initialize the hooks for OMF 5.4 only + + """ + attr = self._attrs["stdin"] + attr.set_hook = self.stdin_hook +
    +
    [docs] def valid_connection(self, guid): + """ Check if the connection with the guid in parameter is possible. + Only meaningful connections are allowed. + + :param guid: Guid of RM it will be connected + :type guid: int + :rtype: Boolean + + """ + rm = self.ec.get_resource(guid) + if rm.get_rtype() not in self._authorized_connections: + msg = ("Connection between %s %s and %s %s refused: " + "An Application can be connected only to a Node" ) % \ + (self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + + return False + + elif len(self.connections) != 0 : + msg = ("Connection between %s %s and %s %s refused: " + "This Application is already connected" ) % \ + (self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + + return False + + else : + msg = "Connection between %s %s and %s %s accepted" % ( + self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + + return True +
    +
    [docs] def do_deploy(self): + """ Deploy the RM. It means nothing special for an application + for now (later it will be upload sources, ...) + It becomes DEPLOYED after the topic for the application has been created + + """ + if not self.node or self.node.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " + % self.node.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + return + + ## For performance test + if self.dperf: + self.begin_deploy_time = tnow() + self.dperf = False + + self._init_command() + + self.set('xmppUser',self.node.get('xmppUser')) + self.set('xmppServer',self.node.get('xmppServer')) + self.set('xmppPort',self.node.get('xmppPort')) + self.set('xmppPassword',self.node.get('xmppPassword')) + self.set('version',self.node.get('version')) + + if not self.get('xmppServer'): + msg = "XmppServer is not initialzed. XMPP Connections impossible" + self.error(msg) + raise RuntimeError, msg + + if not (self.get('xmppUser') or self.get('xmppPort') + or self.get('xmppPassword')): + msg = "Credentials are not all initialzed. Default values will be used" + self.warn(msg) + + if not self.get('command') : + msg = "Application's Command is not initialized" + self.error(msg) + raise RuntimeError, msg + + if not self._omf_api : + self._omf_api = OMFAPIFactory.get_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + if self.get('version') == "5": + + self.begin_deploy_time = tnow() + + if self.get('sources'): + gateway = ResourceGateway.AMtoGateway[self.get('xmppServer')] + user = self.get('sshUser') or self.get('xmppUser') + dst = user + "@"+ gateway + ":" + (out, err), proc = sshfuncs.rcopy(self.get('sources'), dst) + else : + # For OMF 6 : + if not self.create_id: + props = {} + if self.get('command'): + props['application:binary_path'] = self.get('command') + props['application:hrn'] = self.get('command') + props['application:membership'] = self._topic_app + props['application:type'] = "application" + + self.create_id = os.urandom(16).encode('hex') + self._omf_api.frcp_create( self.create_id, self.node.get('hostname'), "application", props = props) + + if self._create_cnt > confirmation_counter: + msg = "Couldn't retrieve the confirmation of the creation" + self.error(msg) + raise RuntimeError, msg + + uid = self.check_deploy(self.create_id) + if not uid: + self._create_cnt +=1 + self.ec.schedule(reschedule_check, self.deploy) + return + + self._topic_app = uid + self._omf_api.enroll_topic(self._topic_app) + + super(OMFApplication, self).do_deploy() +
    +
    [docs] def check_deploy(self, cid): + """ Check, through the mail box in the parser, + if the confirmation of the creation has been received + + :param cid: the id of the original message + :type guid: string + + """ + uid = self._omf_api.check_mailbox("create", cid) + if uid : + return uid + return False +
    +
    [docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + self.info("Retrieving '%s' trace %s " % (name, attr)) + if name == 'stdout' : + suffix = '.out' + elif name == 'stderr' : + suffix = '.err' + else : + suffix = '.misc' + + trace_path = '/tmp/'+ self._topic_app + suffix + + if attr == TraceAttr.PATH: + return trace_path + + if attr == TraceAttr.ALL: + try: + f = open(trace_path ,'r') + except IOError: + print "File with traces has not been found" + return False + out = f.read() + f.close() + return out + +
    +
    [docs] def do_start(self): + """ Start the RM. It means : Send Xmpp Message Using OMF protocol + to execute the application. + + """ + ## For performance test + if self.sperf: + self.begin_start_time = tnow() + self.sperf = False + + if not self.get('env'): + self.set('env', " ") + + if self.get('version') == "5": + self.begin_start_time = tnow() + # Some information to check the command for OMF5 + msg = " " + self.get_rtype() + " ( Guid : " + str(self._guid) +") : " + \ + self.get('appid') + " : " + self._path + " : " + \ + self._args + " : " + self.get('env') + self.debug(msg) + + self._omf_api.execute(self.node.get('hostname'),self.get('appid'), \ + self._args, self._path, self.get('env')) + else: + #For OMF 6 + if self._start_cnt == 0: + props = {} + props['state'] = "running" + + guards = {} + guards['type'] = "application" + guards['name'] = self.get('command') + + self._omf_api.frcp_configure(self._topic_app, props = props, guards = guards ) + + if self._start_cnt > confirmation_counter: + msg = "Couldn't retrieve the confirmation that the application started" + self.error(msg) + raise RuntimeError, msg + + res = self.check_start(self._topic_app) + if not res: + self._start_cnt +=1 + self.ec.schedule(reschedule_check, self.start) + return + + super(OMFApplication, self).do_start() +
    +
    [docs] def check_start(self, uid): + """ Check, through the mail box in the parser, + if the confirmation of the start has been received + + :param uid: the id of the original message + :type guid: string + + """ + res = self._omf_api.check_mailbox("started", uid) + if res : + return True + return False +
    +
    [docs] def do_stop(self): + """ Stop the RM. It means : Send Xmpp Message Using OMF protocol to + kill the application. + State is set to STOPPED after the message is sent. + + """ + + + if self.get('version') == 5: + self._omf_api.exit(self.node.get('hostname'),self.get('appid')) + super(OMFApplication, self).do_stop() +
    +
    [docs] def check_release(self, cid): + """ Check, through the mail box in the parser, + if the confirmation of the release has been received + + :param cid: the id of the original message + :type guid: string + + """ + res = self._omf_api.check_mailbox("release", cid) + if res : + return res + return False +
    +
    [docs] def do_release(self): + """ Clean the RM at the end of the experiment and release the API. + + """ + ## For performance test + if self.rperf: + self.begin_release_time = tnow() + self.rperf = False + + if self._omf_api: + if self.get('version') == "6" and self._topic_app: + if not self.release_id: + self.release_id = os.urandom(16).encode('hex') + self._omf_api.frcp_release( self.release_id, self.node.get('hostname'),self._topic_app, res_id=self._topic_app) + + if self._release_cnt < confirmation_counter: + cid = self.check_release(self.release_id) + if not cid: + self._release_cnt +=1 + self.ec.schedule(reschedule_check, self.release) + return + else: + msg = "Couldn't retrieve the confirmation of the release" + self.error(msg) + + # Remove the stdout and stderr of the application + try: + os.remove('/tmp/'+self._topic_app +'.out') + os.remove('/tmp/'+self._topic_app +'.err') + except OSError: + pass + + OMFAPIFactory.release_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + super(OMFApplication, self).do_release() +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/channel.html new file mode 100644 index 00000000..6ee1dc46 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/channel.html @@ -0,0 +1,291 @@ + + + + + + + + nepi.resources.omf.channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.channel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +from nepi.util.timefuncs import tnow
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.execution.attribute import Attribute, Flags 
    +
    +from nepi.resources.omf.omf_resource import ResourceGateway, OMFResource
    +from nepi.resources.omf.omf_api_factory import OMFAPIFactory
    +
    +
    +@clsinit_copy
    +
    [docs]class OMFChannel(OMFResource): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + :param creds: Credentials to communicate with the rm (XmppClient for OMF) + :type creds: dict + + """ + _rtype = "omf::Channel" + _authorized_connections = ["omf::WifiInterface", "omf::Node"] + + ChannelToFreq = dict({ + "1" : "2412", + "2" : "2417", + "3" : "2422", + "4" : "2427", + "5" : "2432", + "6" : "2437", + "7" : "2442", + "8" : "2447", + "9" : "2452", + "10" : "2457", + "11" : "2462", + "12" : "2467", + "13" : "2472", + }) + + @classmethod + def _register_attributes(cls): + """Register the attributes of an OMF channel + + """ + channel = Attribute("channel", "Name of the application") + cls._register_attribute(channel) + + def __init__(self, ec, guid): + """ + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + super(OMFChannel, self).__init__(ec, guid) + + self._nodes_guid = list() + self.frequency = None + + self._omf_api = None + + # For performance tests + self.perf = True + self.begin_deploy_time = None + + + @property +
    [docs] def exp_id(self): + return self.ec.exp_id +
    +
    [docs] def valid_connection(self, guid): + """ Check if the connection with the guid in parameter is possible. + Only meaningful connections are allowed. + + :param guid: Guid of the current RM + :type guid: int + :rtype: Boolean + + """ + rm = self.ec.get_resource(guid) + if rm.get_rtype() in self._authorized_connections: + msg = "Connection between %s %s and %s %s accepted" % ( + self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + return True + msg = "Connection between %s %s and %s %s refused" % ( + self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + return False +
    + def _get_target(self, conn_set): + """ + Get the couples (host, interface) that uses this channel + + :param conn_set: Connections of the current Guid + :type conn_set: set + :rtype: list + :return: self._nodes_guid + + """ + res = [] + for elt in conn_set: + rm_iface = self.ec.get_resource(elt) + for conn in rm_iface.connections: + rm_node = self.ec.get_resource(conn) + if rm_node.get_rtype() == "omf::Node" and rm_node.get('hostname'): + if rm_iface.state < ResourceState.PROVISIONED or \ + rm_node.state < ResourceState.READY: + return "reschedule" + couple = [rm_node.get('hostname'), rm_iface.alias] + res.append(couple) + return res + +
    [docs] def get_frequency(self, channel): + """ Returns the frequency of a specific channel number + + """ + return OMFChannel.ChannelToFreq[channel] +
    +
    [docs] def do_deploy(self): + """ Deploy the RM. It means : Get the xmpp client and send messages + using OMF 5.4 or 6 protocol to configure the channel. + + """ + + ## For performance test + if self.perf: + self.begin_deploy_time = tnow() + self.perf = False + + if not self.get('channel'): + msg = "Channel's value is not initialized" + self.error(msg) + raise RuntimeError, msg + + if self.get('version') == "6": + self.frequency = self.get_frequency(self.get('channel')) + super(OMFChannel, self).do_deploy() + return + + if not self.get('xmppServer'): + msg = "XmppServer is not initialzed. XMPP Connections impossible" + self.error(msg) + raise RuntimeError, msg + + if not (self.get('xmppUser') or self.get('xmppPort') + or self.get('xmppPassword')): + msg = "Credentials are not all initialzed. Default values will be used" + self.warn(msg) + + if not self._omf_api : + self._omf_api = OMFAPIFactory.get_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + self._nodes_guid = self._get_target(self._connections) + + if self._nodes_guid == "reschedule" : + self.ec.schedule("1s", self.deploy) + else: + for couple in self._nodes_guid: + attrval = self.get('channel') + attrname = "net/%s/%s" % (couple[1], 'channel') + self._omf_api.configure(couple[0], attrname, attrval) + + super(OMFChannel, self).do_deploy() +
    +
    [docs] def do_release(self): + """ Clean the RM at the end of the experiment and release the API + + """ + if self._omf_api : + OMFAPIFactory.release_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + super(OMFChannel, self).do_release() +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/interface.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/interface.html new file mode 100644 index 00000000..2d6f044c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/interface.html @@ -0,0 +1,430 @@ + + + + + + + + nepi.resources.omf.interface — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.interface

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +import os, time
    +from nepi.util.timefuncs import tnow
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.execution.attribute import Attribute, Flags 
    +
    +from nepi.resources.omf.node import OMFNode, confirmation_counter, reschedule_check
    +from nepi.resources.omf.omf_resource import ResourceGateway, OMFResource
    +from nepi.resources.omf.channel import OMFChannel
    +from nepi.resources.omf.omf_api_factory import OMFAPIFactory
    +
    +@clsinit_copy
    +
    [docs]class OMFWifiInterface(OMFResource): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + _rtype = "omf::WifiInterface" + _authorized_connections = ["omf::Node" , "omf::Channel", "wilabt::sfa::Node"] + + @classmethod + def _register_attributes(cls): + """Register the attributes of an OMF interface + + """ + name = Attribute("name","Alias of the interface : wlan0, wlan1, ..", default = "wlan0") + mode = Attribute("mode","Mode of the interface") + hw_mode = Attribute("hw_mode","Choose between : a, b, g, n") + essid = Attribute("essid","Essid of the interface") + ip = Attribute("ip","IP of the interface") + cls._register_attribute(name) + cls._register_attribute(mode) + cls._register_attribute(hw_mode) + cls._register_attribute(essid) + cls._register_attribute(ip) + + def __init__(self, ec, guid): + """ + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + :param creds: Credentials to communicate with the rm (XmppClient for OMF) + :type creds: dict + + """ + super(OMFWifiInterface, self).__init__(ec, guid) + + self._conf = False + self.alias = None + self._type = None + + self.create_id = None + self._create_cnt = 0 + self.release_id = None + self._release_cnt = 0 + self._topic_iface = None + self._omf_api = None + self._type = "" + + # For performance tests + self.perf = True + self.begin_deploy_time = None + +
    [docs] def valid_connection(self, guid): + """ Check if the connection with the guid in parameter is possible. + Only meaningful connections are allowed. + + :param guid: Guid of the current RM + :type guid: int + :rtype: Boolean + + """ + rm = self.ec.get_resource(guid) + if rm.get_rtype() in self._authorized_connections: + msg = "Connection between %s %s and %s %s accepted" % \ + (self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + return True + + msg = "Connection between %s %s and %s %s refused" % \ + (self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + return False +
    + @property +
    [docs] def exp_id(self): + return self.ec.exp_id +
    + @property +
    [docs] def node(self): + rm_list = self.get_connected(OMFNode.get_rtype()) + if rm_list: return rm_list[0] + return None +
    + @property +
    [docs] def channel(self): + rm_list = self.get_connected(OMFChannel.get_rtype()) + if rm_list: return rm_list[0] + return None +
    +
    [docs] def configure_iface(self): + """ Configure the interface without the ip + + """ + if self.node.state < ResourceState.READY: + self.ec.schedule(self.reschedule_delay, self.deploy) + return False + + for attrname in ["mode", "type", "essid"]: + if attrname == "type" : + attrval = self._type + else : + attrval = self.get(attrname) + attrname = "net/%s/%s" % (self.alias, attrname) + self._omf_api.configure(self.node.get('hostname'), attrname, + attrval) + + super(OMFWifiInterface, self).do_provision() + return True +
    +
    [docs] def configure_ip(self): + """ Configure the ip of the interface + + .. note : The ip is separated from the others parameters to avoid + CELL ID shraing problem. By putting th ip at the end of the configuration, + each node use the same channel and can then share the same CELL ID. + In the second case, the channel is defined at the end and the node don't + share a common CELL ID and can not communicate. + + """ + if self.channel.state < ResourceState.READY: + self.ec.schedule(self.reschedule_delay, self.deploy) + return False + + attrval = self.get("ip") + if '/' in attrval: + attrval,mask = attrval.split('/') + attrname = "net/%s/%s" % (self.alias, "ip") + self._omf_api.configure(self.node.get('hostname'), attrname, + attrval) + return True + +
    +
    [docs] def configure_on_omf5(self): + """ Method to configure the wifi interface when OMF 5.4 is used. + + """ + + self._type = self.get('hw_mode') + if self.get('name') == "wlan0" or "eth0": + self.alias = "w0" + else: + self.alias = "w1" + res = False + if self.state < ResourceState.PROVISIONED: + if self._conf == False: + self._conf = self.configure_iface() + if self._conf == True: + res = self.configure_ip() + return res +
    +
    [docs] def check_deploy(self, cid): + """ Check, through the mail box in the parser, + if the confirmation of the creation has been received + + :param cid: the id of the original message + :type guid: string + + """ + uid = self._omf_api.check_mailbox("create", cid) + if uid : + return uid + return False +
    +
    [docs] def do_deploy(self): + """ Deploy the RM. It means : Get the xmpp client and send messages + using OMF 5.4 or 6 protocol to configure the interface. + + """ + if not self.node or self.node.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " + % self.node.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + return + + if not self.channel or self.channel.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- channel state %s " + % self.channel.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + return + + ## For performance test + if self.perf: + self.begin_deploy_time = tnow() + self.perf = False + + self.set('xmppUser',self.node.get('xmppUser')) + self.set('xmppServer',self.node.get('xmppServer')) + self.set('xmppPort',self.node.get('xmppPort')) + self.set('xmppPassword',self.node.get('xmppPassword')) + self.set('version',self.node.get('version')) + + if not self.get('xmppServer'): + msg = "XmppServer is not initialzed. XMPP Connections impossible" + self.error(msg) + raise RuntimeError, msg + + if not (self.get('xmppUser') or self.get('xmppPort') + or self.get('xmppPassword')): + msg = "Credentials are not all initialzed. Default values will be used" + self.warn(msg) + + if not self._omf_api : + self._omf_api = OMFAPIFactory.get_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + if not (self.get('name')): + msg = "Interface's name is not initialized" + self.error(msg) + raise RuntimeError, msg + + if not (self.get('mode') and self.get('essid') \ + and self.get('hw_mode') and self.get('ip')): + msg = "Interface's variable are not initialized" + self.error(msg) + raise RuntimeError, msg + + if self.get('version') == "5": + res = self.configure_on_omf5() + + else : + res = self.configure_on_omf6() + + if res: + super(OMFWifiInterface, self).do_deploy() +
    +
    [docs] def configure_on_omf6(self): + """ Method to configure the wifi interface when OMF 6 is used. + + """ + if not self.create_id : + props = {} + props['wlan:if_name'] = self.get('name') + props['wlan:mode'] = { + "mode": self.get('mode'), + "hw_mode" : self.get('hw_mode'), + "channel" : self.channel.get('channel'), + "essid" : self.get('essid'), + "ip_addr" : self.get('ip'), + "frequency" : self.channel.frequency, + "phy" : "%0%" + } + props['wlan:hrn'] = self.get('name') + props['wlan:type'] = "wlan" + + self.create_id = os.urandom(16).encode('hex') + self._omf_api.frcp_create( self.create_id, self.node.get('hostname'), "wlan", props = props) + + if self._create_cnt > confirmation_counter: + msg = "Couldn't retrieve the confirmation of the creation" + self.error(msg) + raise RuntimeError, msg + + uid = self.check_deploy(self.create_id) + if not uid: + self._create_cnt +=1 + self.ec.schedule(reschedule_check, self.deploy) + return False + + self._topic_iface = uid + self._omf_api.enroll_topic(self._topic_iface) + return True +
    +
    [docs] def check_release(self, cid): + """ Check, through the mail box in the parser, + if the confirmation of the release has been received + + :param cid: the id of the original message + :type guid: string + + """ + res = self._omf_api.check_mailbox("release", cid) + if res : + return res + return False +
    +
    [docs] def do_release(self): + """ Clean the RM at the end of the experiment and release the API + + """ + if self._omf_api: + if self.get('version') == "6" and self._topic_iface : + if not self.release_id: + self.release_id = os.urandom(16).encode('hex') + self._omf_api.frcp_release( self.release_id, self.node.get('hostname'),self._topic_iface, res_id=self._topic_iface) + + if self._release_cnt < confirmation_counter: + cid = self.check_release(self.release_id) + if not cid: + self._release_cnt +=1 + self.ec.schedule(reschedule_check, self.release) + return + else: + msg = "Couldn't retrieve the confirmation of the release" + self.error(msg) + + + OMFAPIFactory.release_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + super(OMFWifiInterface, self).do_release() +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_5_4.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_5_4.html new file mode 100644 index 00000000..96c65136 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_5_4.html @@ -0,0 +1,345 @@ + + + + + + + + nepi.resources.omf.messages_5_4 — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.messages_5_4

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +from xml.etree import cElementTree as ET
    +
    +
    [docs]class MessageHandler(): + """ + .. class:: Class Args : + + :param sliceid: Slice Name (= Xmpp Slice) + :type expid: str + :param expid: Experiment ID (= Xmpp User) + :type expid: str + + .. note:: + + This class is used only for OMF 5.4 Protocol and is going to become unused + + """ + + def __init__(self, sliceid, expid ): + """ + + :param sliceid: Slice Name (= Xmpp Slice) + :type expid: str + :param expid: Experiment ID (= Xmpp User) + :type expid: str + + """ + self._slice_id = sliceid + self._exp_id = expid + + + def _id_element(self, parent, markup): + """ Insert a markup element with an id + + :param parent: Parent element in an XML point of view + :type parent: ElementTree Element + :param markup: Name of the markup + :type markup: str + + """ + elt = ET.SubElement(parent, markup) + elt.set("id", "\'omf-payload\'") + return elt + + def _attr_element(self, parent, markup, text): + """ Insert a markup element with a text (value) + + :param parent: Parent element in an XML point of view + :type parent: ElementTree Element + :param markup: Name of the markup + :type markup: str + :param text: Value of the markup element + :type text: str + + """ + elt = ET.SubElement(parent, markup) + elt.text = text + return elt + +
    [docs] def execute_function(self, target, appid, cmdlineargs, path, env): + """ Build an Execute Message + + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + :param appid: Application id + :type appid: str + :param cmdlineargs: Arguments of the application + :type cmdlineargs: str + :param path: Path of the application + :type path: str + :param env: Environment variables + :type env: str + + """ + payload = ET.Element("omf-message") + execute = self._id_element(payload,"EXECUTE") + env = self._attr_element(execute, "ENV", env) + sliceid = self._attr_element(execute,"SLICEID",self._slice_id) + expid = self._attr_element(execute,"EXPID",self._exp_id) + target = self._attr_element(execute,"TARGET",target) + appid = self._attr_element(execute,"APPID",appid) + cmdlineargs = self._attr_element(execute,"CMDLINEARGS",cmdlineargs) + path = self._attr_element(execute,"PATH",path) + return payload +
    +
    [docs] def stdin_function(self, target, value, appid): + """ Build an Execute Message + + :param value: parameter that go in the stdin + :type value: str + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + :param appid: Application id + :type appid: str + + """ + payload = ET.Element("omf-message") + stdin = self._id_element(payload,"STDIN") + value = self._attr_element(stdin,"VALUE",value) + sliceid = self._attr_element(stdin,"SLICEID",self._slice_id) + expid = self._attr_element(stdin,"EXPID",self._exp_id) + target = self._attr_element(stdin,"TARGET",target) + appid = self._attr_element(stdin,"APPID",appid) + return payload +
    +
    [docs] def exit_function(self, target, appid): + """ Build an Exit Message + + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + :param appid: Application id (ex : vlc#1) + :type appid: str + + """ + payload = ET.Element("omf-message") + execute = self._id_element(payload,"EXIT") + sliceid = self._attr_element(execute,"SLICEID",self._slice_id) + expid = self._attr_element(execute,"EXPID",self._exp_id) + target = self._attr_element(execute,"TARGET",target) + appid = self._attr_element(execute,"APPID",appid) + return payload +
    +
    [docs] def configure_function(self, target, value, path): + """ Build a Configure Message + + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + :param value: guid of the RM + :type value: int + :param path: Path of the element to configure (ex : net/w0/channel) + :type path: dict + + """ + payload = ET.Element("omf-message") + config = self._id_element(payload, "CONFIGURE") + sliceid = self._attr_element(config,"SLICEID",self._slice_id) + expid = self._attr_element(config,"EXPID",self._exp_id) + target = self._attr_element(config,"TARGET",target) + value = self._attr_element(config,"VALUE",value) + path = self._attr_element(config,"PATH",path) + return payload +
    +
    [docs] def log_function(self,level, logger, level_name, data): + """ Build a Log Message + + :param level: Level of logging + :type level: str + :param logger: Element publishing the log + :type logger: str + :param level_name: Name of the level (ex : INFO) + :type level_name: str + :param data: Content to publish + :type data: str + + """ + payload = ET.Element("omf-message") + log = self._id_element(payload, "LOGGING") + level = self._attr_element(log,"LEVEL",level) + sliceid = self._attr_element(log,"SLICEID",self._slice_id) + logger = self._attr_element(log,"LOGGER",logger) + expid = self._attr_element(log,"EXPID",self._exp_id) + level_name = self._attr_element(log,"LEVEL_NAME",level_name) + data = self._attr_element(log,"DATA",data) + return payload +
    +
    [docs] def alias_function(self, name, target): + """ Build an Alias Message + + :param name: Name of the new alias + :type name: str + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + + """ + payload = ET.Element("omf-message") + alias = self._id_element(payload,"ALIAS") + sliceid = self._attr_element(alias,"SLICEID",self._slice_id) + expid = self._attr_element(alias,"EXPID",self._exp_id) + name = self._attr_element(alias,"NAME",name) + target = self._attr_element(alias,"TARGET",target) + return payload +
    +
    [docs] def enroll_function(self, enrollkey, image, index, target ): + """ Build an Enroll Message + + :param enrollkey: Type of enrollment (= 1) + :type enrollkey: str + :param image: Image (= * when all the nodes are concerned) + :type image: str + :param index: Index (= 1 in general) + :type index: str + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + + """ + payload = ET.Element("omf-message") + enroll = self._id_element(payload,"ENROLL") + enrollkey = self._attr_element(enroll,"ENROLLKEY",enrollkey) + sliceid = self._attr_element(enroll,"SLICEID",self._slice_id) + image = self._attr_element(enroll,"IMAGE",image) + expid = self._attr_element(enroll,"EXPID",self._exp_id) + index = self._attr_element(enroll,"INDEX",index) + target = self._attr_element(enroll,"TARGET",target) + return payload +
    +
    [docs] def noop_function(self,target): + """ Build a Noop Message + + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + + """ + payload = ET.Element("omf-message") + noop = self._id_element(payload,"NOOP") + sliceid = self._attr_element(noop,"SLICEID",self._slice_id) + expid = self._attr_element(noop,"EXPID",self._exp_id) + target = self._attr_element(noop,"TARGET",target) + return payload +
    +
    [docs] def newexp_function(self, experimentid, address): + """ Build a NewExp Message + + :param experimentid: Id of the new experiment + :type experimentid: str + :param address: Adress of the destination set of nodes + :type address: str + + """ + payload = ET.Element("omf-message") + newexp = self._id_element(payload,"EXPERIMENT_NEW") + experimentid = self._attr_element(newexp,"EXPERIMENT_ID",experimentid) + sliceid = self._attr_element(newexp,"SLICEID",self._slice_id) + expid = self._attr_element(newexp,"EXPID",self._exp_id) + address = self._attr_element(newexp,"ADDRESS",address) + return payload +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_6.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_6.html new file mode 100644 index 00000000..6e54de86 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_6.html @@ -0,0 +1,343 @@ + + + + + + + + nepi.resources.omf.messages_6 — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.messages_6

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +from xml.etree import cElementTree as ET
    +
    +
    [docs]class MessageHandler(): + """ + .. class:: Class Args : + + :param sliceid: Slice Name (= Xmpp Slice) + :type expid: str + :param expid: Experiment ID (= Xmpp User) + :type expid: str + + .. note:: + + This class is used only for OMF 5.4 Protocol and is going to become unused + + """ + + def __init__(self): + """ + + """ + pass + + def _type_element(self, type_elt, xmlns, msg_id): + """ Insert a markup element with an id + + """ + elt = ET.Element(type_elt) + elt.set("xmlns", xmlns) + elt.set("mid", msg_id) + return elt + + + + def _attr_element(self, parent, markup, text, type_key=None, type_value = None): + """ Insert a markup element with a text (value) + + :param parent: Parent element in an XML point of view + :type parent: ElementTree Element + :param markup: Name of the markup + :type markup: str + :param text: Value of the markup element + :type text: str + + """ + elt = ET.SubElement(parent, markup) + if type_key and type_value: + elt.set(type_key, type_value) + elt.text = text + return elt + + def _id_element(self, parent, markup, key, value): + """ Insert a markup element with a text (value) + + :param parent: Parent element in an XML point of view + :type parent: ElementTree Element + :param markup: Name of the markup + :type markup: str + :param text: Value of the markup element + :type text: str + + """ + elt = ET.SubElement(parent, markup) + elt.set(key, value) + return elt + +
    [docs] def create_function(self, msg_id, src, rtype, timestamp, props = None, guards = None): + """ Build a create message + + :param msg_id: Id of the message + :type msg_id: str + :param src: Src node that send the message (jabber source) + :type src: str + :param rtype: Type of the object + :type rtype: str + :param timestamp: Unix Timestamp + :type timestamp: str + :param props: List of properties + :type props: list + :param guards: list of guards (assertions for properties) + :type guards: list + """ + payload = self._type_element("create", "http://schema.mytestbed.net/omf/6.0/protocol", msg_id ) + self._attr_element(payload,"src",src) + self._attr_element(payload,"ts",timestamp) + self._attr_element(payload,"rtype",rtype) + + if props : + if rtype == "application" : + properties = self._id_element(payload,"props","xmlns:application", + "http://schema.mytestbed.net/omf/6.0/protocol/application") + elif rtype == "wlan" : + properties = self._id_element(payload,"props","xmlns:wlan", + "http://schema.mytestbed.net/omf/6.0/protocol/wlan") + else: + properties = self._attr_element(payload,"props","") + + for prop in props.keys(): + if isinstance(props[prop],str): + self._attr_element(properties,prop,props[prop],type_key="type", type_value = "string") + elif isinstance(props[prop],dict): + key = self._attr_element(properties,prop,"",type_key="type", type_value = "hash") + for comp in props[prop].keys(): + self._attr_element(key,comp,props[prop][comp],type_key="type", type_value = "string") + + if guards : + guardians = self._attr_element(payload,"guard","") + for guard in guards.keys(): + self._attr_element(guardians,guard,guards[guard],type_key="type", type_value = "string") + + return payload +
    +
    [docs] def configure_function(self, msg_id, src, timestamp, props = None, guards = None): + """ Build a configure message + + :param msg_id: Id of the message + :type msg_id: str + :param src: Src node that send the message (jabber source) + :type src: str + :param timestamp: Unix Timestamp + :type timestamp: str + :param props: List of properties + :type props: list + :param guards: list of guards (assertions for properties) + :type guards: list + """ + payload = self._type_element("configure", "http://schema.mytestbed.net/omf/6.0/protocol", msg_id ) + self._attr_element(payload,"src",src) + self._attr_element(payload,"ts",timestamp) + + if props : + properties = self._attr_element(payload,"props","") + for prop in props.keys(): + self._attr_element(properties,prop,props[prop],type_key="type", type_value = "symbol") + + if guards : + guardians = self._attr_element(payload,"guard","") + for guard in guards.keys(): + self._attr_element(guardians,guard,guards[guard],type_key="type", type_value = "string") + + return payload +
    +
    [docs] def request_function(self, msg_id, src, timestamp, props = None, guards = None): + """ Build a request message + + :param msg_id: Id of the message + :type msg_id: str + :param src: Src node that send the message (jabber source) + :type src: str + :param timestamp: Unix Timestamp + :type timestamp: str + :param props: List of properties + :type props: list + :param guards: list of guards (assertions for properties) + :type guards: list + """ + payload = self._type_element("request", "http://schema.mytestbed.net/omf/6.0/protocol", msg_id ) + self._attr_element(payload,"src",src) + self._attr_element(payload,"ts",timestamp) + + if props : + properties = self._attr_element(payload,"props","") + for prop in props.keys(): + self._attr_element(properties,prop,props[prop]) + + if guards : + guardians = self._attr_element(payload,"guard","") + for guard in guards.keys(): + self._attr_element(guardians,guard,guards[guard]) + return payload + +# For now, we don't need the inform message since it is ht RC that send them. + +# def inform_function(self, msg_id, src, timestamp, cid, itype): +# """ Build an inform message + +# :param msg_id: Id of the message +# :type msg_id: str +# :param src: Src node that send the message (jabber source) +# :type src: str +# :param rtype: Type of the object +# :type rtype: str +# :param timestamp: Unix Timestamp +# :type timestamp: str +# :param cid: Id of the orignial message +# :type cid: str +# :param itype: type of the object created +# :type itype: str +# """ + +# payload = self._type_element("inform", "http://schema.mytestbed.net/omf/6.0/protocol", msg_id ) +# sliceid = self._attr_element(payload,"src",src) +# expid = self._attr_element(config,"ts",timestamp) +# target = self._attr_element(config,"cid",cid) +# value = self._attr_element(config,"itype",value) +# path = self._attr_element(config,"properties",path) +# return payload +
    +
    [docs] def release_function(self, msg_id, src, timestamp, res_id = None, props = None, guards = None): + """ Build a release message + + :param msg_id: Id of the message + :type msg_id: str + :param src: Src node that send the message (jabber source) + :type src: str + :param timestamp: Unix Timestamp + :type timestamp: str + :param res_id: Id of the release resource + :type res_id: str + :param props: List of properties + :type props: list + :param guards: list of guards (assertions for properties) + :type guards: list + """ + payload = self._type_element("release", "http://schema.mytestbed.net/omf/6.0/protocol", msg_id ) + self._attr_element(payload,"src",src) + self._attr_element(payload,"ts",timestamp) + if res_id : + self._attr_element(payload,"res_id",res_id) + + if props : + properties = self._id_element(payload,"props","xmlns:frcp", + "http://schema.mytestbed.net/omf/6.0/protocol") + for prop in props.keys(): + self._attr_element(properties,prop,props[prop]) + + if guards : + guardians = self._attr_element(payload,"guard","") + for guard in guards.keys(): + self._attr_element(guardians,guard,guards[guard]) + + return payload +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/node.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/node.html new file mode 100644 index 00000000..8648767c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/node.html @@ -0,0 +1,267 @@ + + + + + + + + nepi.resources.omf.node — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.node

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +from nepi.util.timefuncs import tnow
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.execution.attribute import Attribute, Flags 
    +from nepi.resources.omf.omf_resource import ResourceGateway, OMFResource
    +from nepi.resources.omf.omf_api_factory import OMFAPIFactory
    +
    +import time
    +
    +reschedule_check = "1s"
    +confirmation_counter = 3600
    +
    +@clsinit_copy
    +
    [docs]class OMFNode(OMFResource): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + :param creds: Credentials to communicate with the rm (XmppClient for OMF) + :type creds: dict + + """ + _rtype = "omf::Node" + _authorized_connections = ["omf::Application" , "omf::WifiInterface"] + + @classmethod + def _register_attributes(cls): + """Register the attributes of an OMF Node + + """ + hostname = Attribute("hostname", "Hostname of the machine") + + cls._register_attribute(hostname) + + # XXX: We don't necessary need to have the credentials at the + # moment we create the RM + def __init__(self, ec, guid): + """ + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + super(OMFNode, self).__init__(ec, guid) + + self._omf_api = None + + # For performance tests + self.perf = True + self.begin_deploy_time = None + + + @property +
    [docs] def exp_id(self): + return self.ec.exp_id +
    +
    [docs] def valid_connection(self, guid): + """ Check if the connection with the guid in parameter is possible. + Only meaningful connections are allowed. + + :param guid: Guid of the current RM + :type guid: int + :rtype: Boolean + + """ + rm = self.ec.get_resource(guid) + if rm.get_rtype() in self._authorized_connections: + msg = "Connection between %s %s and %s %s accepted" % ( + self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + return True + + msg = "Connection between %s %s and %s %s refused" % ( + self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.error(msg) + + return False +
    +
    [docs] def do_deploy(self): + """ Deploy the RM. It means : Send Xmpp Message Using OMF protocol + to enroll the node into the experiment. + + """ + ## For performance test + if self.perf: + self.begin_deploy_time = tnow() + self.perf = False + + if not self.get('xmppServer'): + msg = "XmppServer is not initialzed. XMPP Connections impossible" + self.error(msg) + raise RuntimeError, msg + + if not self.get('version'): + msg = "Version of OMF is not indicated" + self.error(msg) + raise RuntimeError, msg + + if not (self.get('xmppUser') or self.get('xmppPort') + or self.get('xmppPassword')): + msg = "Credentials are not all initialzed. Default values will be used" + self.warn(msg) + + if not self._omf_api : + self._omf_api = OMFAPIFactory.get_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + if not self.get('hostname') : + msg = "Hostname's value is not initialized" + self.error(msg) + raise RuntimeError, msg + + if self.get('version') == "5": + self._omf_api.enroll_host(self.get('hostname')) + else: + self._omf_api.enroll_topic(self.get('hostname')) + + super(OMFNode, self).do_deploy() +
    +
    [docs] def do_release(self): + """ Clean the RM at the end of the experiment by unenrolling + the node from the topic + + """ + from nepi.resources.omf.application import OMFApplication + rm_list = self.get_connected(OMFApplication.get_rtype()) + if rm_list: + for rm in rm_list: + if rm.state < ResourceState.RELEASED: + self.ec.schedule(self.reschedule_delay, self.release) + return + + from nepi.resources.omf.interface import OMFWifiInterface + rm_list = self.get_connected(OMFWifiInterface.get_rtype()) + if rm_list: + for rm in rm_list: + if rm.state < ResourceState.RELEASED: + self.ec.schedule(self.reschedule_delay, self.release) + return + + if self._omf_api: + if self.get('version') == "5": + self._omf_api.release(self.get('hostname')) + else: + self._omf_api.unenroll_topic(self.get('hostname')) + + OMFAPIFactory.release_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + super(OMFNode, self).do_release() +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf5_api.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf5_api.html new file mode 100644 index 00000000..fae34e80 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf5_api.html @@ -0,0 +1,402 @@ + + + + + + + + nepi.resources.omf.omf5_api — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.omf5_api

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +import ssl
    +import sys
    +import time
    +
    +from nepi.util.logger import Logger
    +
    +from nepi.resources.omf.omf_client import OMFClient
    +from nepi.resources.omf.messages_5_4 import MessageHandler
    +
    +
    [docs]class OMF5API(Logger): + """ + .. class:: Class Args : + + :param host: Xmpp Server + :type host: str + :param slice: Xmpp Slice + :type slice: str + :param port: Xmpp Port + :type port: str + :param password: Xmpp password + :type password: str + :param xmpp_root: Root of the Xmpp Topic Architecture + :type xmpp_root: str + + .. note:: + + This class is the implementation of an OMF 5.4 API. + Since the version 5.4.1, the Topic Architecture start with OMF_5.4 + instead of OMF used for OMF5.3 + + """ + def __init__(self, host, slice, port, password, xmpp_root = None, + exp_id = None): + """ + :param host: Xmpp Server + :type host: str + :param slice: Xmpp Slice + :type slice: str + :param port: Xmpp Port + :type port: str + :param password: Xmpp password + :type password: str + :param xmpp_root: Root of the Xmpp Topic Architecture + :type xmpp_root: str + + """ + super(OMF5API, self).__init__("OMF5API") + self._exp_id = exp_id + self._user = "%s-%s" % (slice, self._exp_id) + self._slice = slice + self._host = host + self._port = port + self._password = password + self._hostnames = [] + self._xmpp_root = xmpp_root or "OMF_5.4" + + # OMF xmpp client + self._client = None + + # message handler + self._message = None + + if sys.version_info < (3, 0): + reload(sys) + sys.setdefaultencoding('utf8') + + # instantiate the xmpp client + self._init_client() + + # register xmpp nodes for the experiment + self._enroll_experiment() + self._enroll_newexperiment() + + # register xmpp logger for the experiment + self._enroll_logger() + + def _init_client(self): + """ Initialize XMPP Client + + """ + jid = "%s@%s" % (self._user, self._host) + xmpp = OMFClient(jid, self._password) + # PROTOCOL_SSLv3 required for compatibility with OpenFire + xmpp.ssl_version = ssl.PROTOCOL_SSLv3 + + if xmpp.connect((self._host, self._port)): + xmpp.process(block=False) + while not xmpp.ready: + time.sleep(1) + self._client = xmpp + self._message = MessageHandler(self._slice, self._user) + else: + msg = "Unable to connect to the XMPP server." + self.error(msg) + raise RuntimeError(msg) + + def _enroll_experiment(self): + """ Create and Subscribe to the Session Topic + + """ + xmpp_node = self._exp_session_id + self._client.create(xmpp_node) + #print "Create experiment sesion id topics !!" + self._client.subscribe(xmpp_node) + #print "Subscribe to experiment sesion id topics !!" + + + def _enroll_newexperiment(self): + """ Publish New Experiment Message + + """ + address = "/%s/%s/%s/%s" % (self._host, self._xmpp_root, self._slice, + self._user) + #print address + payload = self._message.newexp_function(self._user, address) + slice_sid = "/%s/%s" % (self._xmpp_root, self._slice) + self._client.publish(payload, slice_sid) + + def _enroll_logger(self): + """ Create and Subscribe to the Logger Topic + + """ + xmpp_node = self._logger_session_id + self._client.create(xmpp_node) + self._client.subscribe(xmpp_node) + + payload = self._message.log_function("2", + "nodeHandler::NodeHandler", + "INFO", + "OMF Experiment Controller 5.4 (git 529a626)") + self._client.publish(payload, xmpp_node) + + def _host_session_id(self, hostname): + """ Return the Topic Name as /xmpp_root/slice/user/hostname + + :param hostname: Full hrn of the node + :type hostname: str + + """ + return "/%s/%s/%s/%s" % (self._xmpp_root, self._slice, self._user, + hostname) + + def _host_resource_id(self, hostname): + """ Return the Topic Name as /xmpp_root/slice/resources/hostname + + :param hostname: Full hrn of the node + :type hostname: str + + """ + return "/%s/%s/resources/%s" % (self._xmpp_root, self._slice, hostname) + + @property + def _exp_session_id(self): + """ Return the Topic Name as /xmpp_root/slice/user + + """ + return "/%s/%s/%s" % (self._xmpp_root, self._slice, self._user) + + @property + def _logger_session_id(self): + """ Return the Topic Name as /xmpp_root/slice/LOGGER + + """ + return "/%s/%s/%s/LOGGER" % (self._xmpp_root, self._slice, self._user) + +
    [docs] def delete(self, hostname): + """ Delete the topic corresponding to the hostname for this session + + :param hostname: Full hrn of the node + :type hostname: str + + """ + if not hostname in self._hostnames: + return + + self._hostnames.remove(hostname) + + xmpp_node = self._host_session_id(hostname) + self._client.delete(xmpp_node) +
    +
    [docs] def enroll_host(self, hostname): + """ Create and Subscribe to the session topic and the resources + corresponding to the hostname + + :param hostname: Full hrn of the node + :type hostname: str + + """ + if hostname in self._hostnames: + return + + self._hostnames.append(hostname) + + xmpp_node = self._host_session_id(hostname) + self._client.create(xmpp_node) + self._client.subscribe(xmpp_node) + + xmpp_node = self._host_resource_id(hostname) + self._client.subscribe(xmpp_node) + + payload = self._message.enroll_function("1", "*", "1", hostname) + self._client.publish(payload, xmpp_node) +
    +
    [docs] def configure(self, hostname, attribute, value): + """ Configure attribute on the node + + :param hostname: Full hrn of the node + :type hostname: str + :param attribute: Attribute that need to be configured ( + often written as /net/wX/attribute, with X the interface number) + :type attribute: str + :param value: Value of the attribute + :type value: str + + """ + payload = self._message.configure_function(hostname, value, attribute) + xmpp_node = self._host_session_id(hostname) + self._client.publish(payload, xmpp_node) + +
    +
    [docs] def send_stdin(self, hostname, value, app_id): + """ Send to the stdin of the application the value + + :param hostname: Full hrn of the node + :type hostname: str + :param appid: Application Id (Any id that represents in a unique + way the application) + :type appid: str + :param value: parameter to execute in the stdin of the application + :type value: str + + """ + payload = self._message.stdin_function(hostname, value, app_id) + xmpp_node = self._host_session_id(hostname) + self._client.publish(payload, xmpp_node) + +
    +
    [docs] def execute(self, hostname, app_id, arguments, path, env): + """ Execute command on the node + + :param hostname: Full hrn of the node + :type hostname: str + :param app_id: Application Id (Any id that represents in a unique + way the application) + :type app_id: str + :param arguments: Arguments of the application + :type arguments: str + :param path: Path of the application + :type path: str + :param env: Environnement values for the application + :type env: str + + """ + payload = self._message.execute_function(hostname, app_id, arguments, + path, env) + xmpp_node = self._host_session_id(hostname) + self._client.publish(payload, xmpp_node) +
    +
    [docs] def exit(self, hostname, app_id): + """ Kill an application started with OMF + + :param hostname: Full hrn of the node + :type hostname: str + :param app_id: Application Id of the application you want to stop + :type app_id: str + + """ + payload = self._message.exit_function(hostname, app_id) + xmpp_node = self._host_session_id(hostname) + self._client.publish(payload, xmpp_node) +
    +
    [docs] def release(self, hostname): + """ Delete the session and logger topics. Then disconnect + + """ + if hostname in self._hostnames: + self.delete(hostname) +
    +
    [docs] def disconnect(self) : + """ Delete the session and logger topics. Then disconnect + + """ + self._client.delete(self._exp_session_id) + self._client.delete(self._logger_session_id) + + time.sleep(1) + + # Wait the send queue to be empty before disconnect + self._client.disconnect(wait=True) + msg = " Disconnected from XMPP Server" + self.debug(msg) +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_api.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_api.html new file mode 100644 index 00000000..4e069bfa --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_api.html @@ -0,0 +1,351 @@ + + + + + + + + nepi.resources.omf.omf6_api — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.omf6_api

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +import ssl
    +import sys
    +import time
    +
    +from nepi.util.timefuncs import tsformat 
    +import os
    +
    +from nepi.util.logger import Logger
    +
    +from nepi.resources.omf.omf_client import OMFClient
    +from nepi.resources.omf.messages_6 import MessageHandler
    +
    +
    [docs]class OMF6API(Logger): + """ + .. class:: Class Args : + + :param server: Xmpp Server + :type server: str + :param user: Xmpp User + :type user: str + :param port: Xmpp Port + :type port: str + :param password: Xmpp password + :type password: str + :param xmpp_root: Root of the Xmpp Topic Architecture + :type xmpp_root: str + + .. note:: + + This class is the implementation of an OMF 5.4 API. + Since the version 5.4.1, the Topic Architecture start with OMF_5.4 + instead of OMF used for OMF5.3 + + """ + def __init__(self, server, user = "nepi", port="5222", password="1234", + exp_id = None): + """ + :param server: Xmpp Server + :type server: str + :param user: Xmpp User + :type user: str + :param port: Xmpp Port + :type port: str + :param password: Xmpp password + :type password: str + :param xmpp_root: Root of the Xmpp Topic Architecture + :type xmpp_root: str + + """ + super(OMF6API, self).__init__("OMF6API") + self._exp_id = exp_id + self._user = user # name of the machine that run Nepi + self._server = server # name of the xmpp server + self._port = port # port of the xmpp server + self._password = password # password to connect to xmpp + self._jid = "%s-%s@%s" % (self._user, self._exp_id, self._server) + self._src = "xmpp://" + self._jid + + self._topics = [] + + # OMF xmpp client + self._client = None + + # message handler + self._message = None + + if sys.version_info < (3, 0): + reload(sys) + sys.setdefaultencoding('utf8') + + # instantiate the xmpp client + self._init_client() + + # register nepi topic + self._enroll_nepi() + + + def _init_client(self): + """ Initialize XMPP Client + + """ + xmpp = OMFClient(self._jid, self._password) + # PROTOCOL_SSLv3 required for compatibility with OpenFire + xmpp.ssl_version = ssl.PROTOCOL_SSLv3 + + if xmpp.connect((self._server, self._port)): + xmpp.process(block=False) + self.check_ready(xmpp) + self._client = xmpp + self._message = MessageHandler() + else: + msg = "Unable to connect to the XMPP server." + self.error(msg) + raise RuntimeError(msg) + +
    [docs] def check_ready(self, xmpp): + delay = 1.0 + for i in xrange(15): + if xmpp.ready: + break + else: + time.sleep(delay) + delay = delay * 1.5 + else: + msg = "XMPP Client is not ready after long time" + self.error(msg) + raise RuntimeError, msg +
    + @property + def _nepi_topic(self): + """ Return the name of the session topic + + """ + msg = "nepi-" + self._exp_id + self.debug(msg) + return msg + + def _enroll_nepi(self): + """ Create and Subscribe to the session Topic + + """ + nepi_topic = self._nepi_topic + self._client.create(nepi_topic) + self._client.subscribe(nepi_topic) + + +
    [docs] def create_and_enroll_topic(self, topic): + """ Create and Subscribe to the session topic and the resources + corresponding to the hostname + + :param hostname: Full hrn of the node + :type hostname: str + + """ + if topic in self._topics: + return + + self._topics.append(topic) + + self._client.create(topic) + self._client.subscribe(topic) + +
    +
    [docs] def enroll_topic(self, topic): + """ Create and Subscribe to the session topic and the resources + corresponding to the hostname + + """ + if topic in self._topics: + return + + self._topics.append(topic) + self._client.subscribe(topic) + +
    +
    [docs] def frcp_inform(self, topic, cid, itype): + """ Publish an inform message + + """ + msg_id = os.urandom(16).encode('hex') + timestamp = tsformat() + payload = self._message.inform_function(msg_id, self._src, timestamp, props = props ,guards = guards) + + self._client.publish(payload, xmpp_node) +
    +
    [docs] def frcp_configure(self, topic, props = None, guards = None ): + """ Publish a configure message + + """ + msg_id = os.urandom(16).encode('hex') + timestamp = tsformat() + payload = self._message.configure_function(msg_id, self._src, timestamp ,props = props ,guards = guards) + self._client.publish(payload, topic) + +
    +
    [docs] def frcp_create(self, msg_id, topic, rtype, props = None, guards = None ): + """ Publish a create message + + """ + timestamp = tsformat() + payload = self._message.create_function(msg_id, self._src, rtype, timestamp , props = props ,guards = guards) + self._client.publish(payload, topic) + +
    +
    [docs] def frcp_request(self, topic, props = None, guards = None ): + """ Execute command on the node + + """ + msg_id = os.urandom(16).encode('hex') + timestamp = tsformat() + payload = self._message.request_function(msg_id, self._src, timestamp, props = props ,guards = guards) + self._client.publish(payload, xmpp_node) +
    +
    [docs] def frcp_release(self, msg_id, parent, child, res_id = None, props = None, guards = None ): + """ Publish a release message + + """ + timestamp = tsformat() + payload = self._message.release_function(msg_id, self._src, timestamp, res_id = res_id, props = props ,guards = guards) + self._client.publish(payload, parent) + + if child in self._topics: + self._topics.remove(child) + + self._client.unsubscribe(child) + #self._client.delete(child) +
    +
    [docs] def check_mailbox(self, itype, attr): + """ Check the mail box + + :param itype: type of mail + :type itype: str + :param attr: value wanted + :type attr: str + + """ + return self._client.check_mailbox(itype, attr) +
    +
    [docs] def unenroll_topic(self, topic): + """ Create and Subscribe to the session topic and the resources + corresponding to the hostname + + """ + if topic in self._topics: + self._topics.remove(topic) + self._client.unsubscribe(topic) +
    +
    [docs] def disconnect(self) : + """ Delete the session and logger topics. Then disconnect + + """ + # To receive the last messages + time.sleep(2) + + self._client.delete(self._nepi_topic) + + # Wait the send queue to be empty before disconnect + self._client.disconnect(wait=True) + msg = " Disconnected from XMPP Server" + self.debug(msg) +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_parser.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_parser.html new file mode 100644 index 00000000..4f79178b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_parser.html @@ -0,0 +1,382 @@ + + + + + + + + nepi.resources.omf.omf6_parser — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.omf6_parser

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +from nepi.util.logger import Logger
    +
    +import os
    +import traceback
    +import xml.etree.ElementTree as ET
    +
    +# inherit from BaseXmpp and XMLstream classes
    +
    [docs]class OMF6Parser(Logger): + """ + .. class:: Class Args : + + :param jid: Jabber Id (= Xmpp Slice + Date) + :type jid: str + :param password: Jabber Password (= Xmpp Password) + :type password: str + + .. note:: + + This class is an XMPP Client with customized method + + """ + + def __init__(self): + """ + + :param jid: Jabber Id (= Xmpp Slice + Date) + :type jid: str + :param password: Jabber Password (= Xmpp Password) + :type password: str + + + """ + super(OMF6Parser, self).__init__("OMF6API") + self.mailbox={} + self.traces={} + self.trace='NULL' + + self.init_mailbox() + + +
    [docs] def init_mailbox(self): + self.mailbox['create'] = [] + self.mailbox['started'] = [] + self.mailbox['release'] = [] +
    + def _check_for_tag(self, root, namespaces, tag): + """ Check if an element markup is in the ElementTree + + :param root: Root of the tree + :type root: ElementTree Element + :param namespaces: Namespaces of the element + :type namespaces: str + :param tag: Tag that will search in the tree + :type tag: str + + """ + for element in root.iter(namespaces+tag): + if element.text: + return element.text + else : + return None + + def _check_for_props(self, root, namespaces): + """ Check if an element markup is in the ElementTree + + :param root: Root of the tree + :type root: ElementTree Element + :param namespaces: Namespaces of the element + :type namespaces: str + + """ + props = {} + for properties in root.iter(namespaces+'props'): + for element in properties.iter(): + if element.tag and element.text: + props[element.tag] = element.text + return props + + def _check_for_membership(self, root, namespaces): + """ Check if an element markup is in the ElementTree + + :param root: Root of the tree + :type root: ElementTree Element + :param namespaces: Namespaces of the element + :type namespaces: str + + """ + for element in root.iter(namespaces+'membership'): + for elt in element.iter(namespaces+'it'): + ##XXX : change + return elt.text + + + def _check_output(self, root, namespaces): + """ Check the significative element in the answer and display it + + :param root: Root of the tree + :type root: ElementTree Element + :param namespaces: Namespaces of the tree + :type namespaces: str + + """ + fields = ["TARGET", "REASON", "PATH", "APPID", "VALUE"] + response = "" + for elt in fields: + msg = self._check_for_tag(root, namespaces, elt) + if msg is not None: + response = response + " " + msg.text + " :" + deb = self._check_for_tag(root, namespaces, "MESSAGE") + if deb is not None: + msg = response + " " + deb.text + self.debug(msg) + else : + self.info(response) + + + def _inform_creation_ok(self, root, namespaces): + """ Parse and Display CREATION OK message + + """ + #ET.dump(root) + uid = self._check_for_tag(root, namespaces, "uid") + cid = self._check_for_tag(root, namespaces, "cid") + member = self._check_for_membership(root, namespaces) + binary_path = self._check_for_tag(root, namespaces, "binary_path") + msg = "CREATION OK -- " + if binary_path : + msg = msg + "The resource : '"+binary_path + else : + msg = msg + "The interface" + if uid : + msg = msg + "' is listening to the topics : '"+ uid + if member : + msg = msg + "' and '"+ member +"'" + if cid: + self.info(msg) + self.mailbox['create'].append([cid, uid ]) + + def _inform_creation_failed(self, root, namespaces): + """ Parse and Display CREATION FAILED message + + """ + reason = self._check_for_tag(root, namespaces, "reason") + cid = self._check_for_tag(root, namespaces, "cid") + msg = "CREATION FAILED - The reason : "+reason + if cid: + self.error(msg) + self.mailbox['create'].append([cid, uid ]) + + def _inform_status(self, root, namespaces): + """ Parse and Display STATUS message + + """ + props = self._check_for_props(root, namespaces) + uid = self._check_for_tag(root, namespaces, "uid") + event = self._check_for_tag(root, namespaces, "event") + + log = "STATUS -- " + for elt in props.keys(): + ns, tag = elt.split('}') + if tag == "it": + log = log + "membership : " + props[elt]+" -- " + elif tag == "event": + self.mailbox['started'].append(uid) + log = log + "event : " + props[elt]+" -- " + elif tag == "msg": + if event == "STDOUT" : + filename = os.path.join("/tmp", "%s.out" % uid) + f = open(filename,'a+') + # XXX: Adding fake \n for visual formatting + msg = props[elt] # + "\n" + f.write(msg) + f.close() + elif event == "STDERR" : + filename = os.path.join("/tmp", "%s.err" % uid) + f = open(filename,'a+') + # XXX: Adding fake \n for visual formatting + msg = props[elt] # + "\n" + f.write(msg) + f.close() + log = log + tag +" : " + props[elt]+" -- " + else: + log = log + tag +" : " + props[elt]+" -- " + log = log + " STATUS " + self.info(log) + + def _inform_released(self, root, namespaces): + """ Parse and Display RELEASED message + + """ + #ET.dump(root) + parent_id = self._check_for_tag(root, namespaces, "src") + child_id = self._check_for_tag(root, namespaces, "res_id") + cid = self._check_for_tag(root, namespaces, "cid") + if cid : + msg = "RELEASED - The resource : '"+child_id+ \ + "' has been released by : '"+ parent_id + self.info(msg) + self.mailbox['release'].append(cid) + + def _inform_error(self, root, namespaces): + """ Parse and Display ERROR message + + """ + reason = self._check_for_tag(root, namespaces, "reason") + msg = "The reason : "+reason + self.error(msg) + + def _inform_warn(self, root, namespaces): + """ Parse and Display WARN message + + """ + reason = self._check_for_tag(root, namespaces, "reason") + msg = "The reason : "+reason + self.warn(msg) + + def _parse_inform(self, root, namespaces): + """ Check the significative element in the answer + Then Parse it and display using specific method + + :param root: Root of the tree + :type root: ElementTree Element + :param namespaces: Namespaces of the tree + :type namespaces: str + + """ + itype = self._check_for_tag(root, namespaces, "itype") + if itype : + method_name = '_inform_'+ itype.replace('.', '_').lower() + method = getattr(self, method_name) + if method : + method(root, namespaces) + else : + msg = "There is no method to parse the response of the type " + itype + self.info(msg) + return + + +
    [docs] def check_mailbox(self, itype, attr): + """ Check the mail box + + :param itype: type of mail + :type itype: str + :param attr: value wanted + :type attr: str + + """ + if itype == "create": + for res in self.mailbox[itype]: + binary, uid = res + if binary == attr: + self.mailbox[itype].remove(res) + return uid + else : + for res in self.mailbox[itype]: + if attr == res: + self.mailbox[itype].remove(res) + return res + +
    +
    [docs] def handle(self, iq): + """ Check the mail box + + :param iq: message received + :type itype: iq + """ + namespaces = "{http://schema.mytestbed.net/omf/6.0/protocol}" + for i in iq['pubsub_event']['items']: + root = ET.fromstring(str(i)) + #ET.dump(root) + self._parse_inform(root, namespaces) +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_api_factory.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_api_factory.html new file mode 100644 index 00000000..3e59d3b6 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_api_factory.html @@ -0,0 +1,230 @@ + + + + + + + + nepi.resources.omf.omf_api_factory — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.omf_api_factory

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +
    +import time
    +import hashlib
    +import threading
    +
    +from nepi.resources.omf.omf5_api import OMF5API
    +from nepi.resources.omf.omf6_api import OMF6API
    +
    +
    [docs]class OMFAPIFactory(object): + """ + .. note:: + + It allows the different RM to use the same xmpp client if they use + the same credentials. For the moment, it is focused on XMPP. + + """ + # use lock to avoid concurrent access to the Api list at the same times by 2 + # different threads + lock = threading.Lock() + _apis = dict() + + @classmethod +
    [docs] def get_api(cls, version, server, user, port, password, exp_id = None): + """ Get an OMF Api + + :param version: OMF Version. Either 5 or 6 + :type version: str + :param server: Xmpp Server Adress + :type server: str + :param user: Xmpp User + :type user: str + :param port: Xmpp Port (Default : 5222) + :type port: str + :param password: Xmpp Password + :type password: str + :param exp_id: Id of the experiment + :type exp_id: str + + """ + if version and user and server and port and password: + key = cls._make_key(version, server, user, port, password, exp_id) + cls.lock.acquire() + if key in cls._apis: + #print "Api Counter : " + str(cls._apis[key]['cnt']) + cls._apis[key]['cnt'] += 1 + cls.lock.release() + return cls._apis[key]['api'] + else : + omf_api = cls.create_api(version, server, user, port, password, exp_id) + cls.lock.release() + return omf_api + return None +
    + @classmethod +
    [docs] def create_api(cls, version, server, user, port, password, exp_id): + """ Create an OMF API if this one doesn't exist yet with this credentials + + :param version: OMF Version. Either 5 or 6 + :type version: str + :param server: Xmpp Server Adress + :type server: str + :param user: Xmpp User + :type user: str + :param port: Xmpp Port (Default : 5222) + :type port: str + :param password: Xmpp Password + :type password: str + :param exp_id: Id of the experiment + :type exp_id: str + + """ + key = cls._make_key(version, server, user, port, password, exp_id) + if version == "5": + omf_api = OMF5API(server, user, port, password, exp_id = exp_id) + else : + omf_api = OMF6API(server, user = user, port = port, password = password, exp_id = exp_id) + cls._apis[key] = {} + cls._apis[key]['api'] = omf_api + cls._apis[key]['cnt'] = 1 + return omf_api +
    + @classmethod +
    [docs] def release_api(cls, version, server, user, port, password, exp_id = None): + """ Release an OMF API with this credentials + + :param version: OMF Version. Either 5 or 6 + :type version: str + :param server: Xmpp Server Adress + :type server: str + :param user: Xmpp User + :type user: str + :param port: Xmpp Port (Default : 5222) + :type port: str + :param password: Xmpp Password + :type password: str + :param exp_id: Id of the experiment + :type exp_id: str + + """ + if version and user and server and port and password: + key = cls._make_key(version, server, user, port, password, exp_id) + if key in cls._apis: + cls._apis[key]['cnt'] -= 1 + #print "Api Counter : " + str(cls._apis[key]['cnt']) + if cls._apis[key]['cnt'] == 0: + omf_api = cls._apis[key]['api'] + omf_api.disconnect() + del cls._apis[key] +
    + @classmethod + def _make_key(cls, *args): + """ Hash the credentials in order to create a key + + :param args: list of arguments used to create the hash (server, user, port, ...) + :type args: list + + """ + skey = "".join(map(str, args)) + return hashlib.md5(skey).hexdigest() +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_client.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_client.html new file mode 100644 index 00000000..52922bc5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_client.html @@ -0,0 +1,449 @@ + + + + + + + + nepi.resources.omf.omf_client — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.omf_client

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +from nepi.util.logger import Logger
    +from nepi.resources.omf.omf6_parser import OMF6Parser
    +try:
    +    import sleekxmpp
    +    from sleekxmpp.exceptions import IqError, IqTimeout
    +    class BaseOMFClient(sleekxmpp.ClientXMPP):
    +        pass
    +except ImportError:
    +    msg = ("SleekXMPP is not installed. Without this library "
    +          "you will be not able to use OMF Resources "
    +          "if you want to install SleekXmpp: \n"
    +          " git clone -b develop git://github.com/fritzy/SleekXMPP.git \n"
    +          " cd SleekXMPP \n"
    +          " sudo python setup.py install\n")
    +
    +    logger = Logger("BaseOMFClient")
    +    logger.debug(msg)
    +
    +
    [docs] class BaseOMFClient(object): + pass +
    +import traceback +import xml.etree.ElementTree as ET + +# inherit from BaseXmpp and XMLstream classes +
    [docs]class OMFClient(BaseOMFClient, Logger): + """ + .. class:: Class Args : + + :param jid: Jabber Id (= Xmpp Slice + Date) + :type jid: str + :param password: Jabber Password (= Xmpp Password) + :type password: str + + .. note:: + + This class is an XMPP Client with customized method + + """ + + def __init__(self, jid, password): + """ + + :param jid: Jabber Id (= Xmpp Slice + Date) + :type jid: str + :param password: Jabber Password (= Xmpp Password) + :type password: str + + + """ + Logger.__init__(self, "OMFClient") + + sleekxmpp.ClientXMPP.__init__(self, jid, password) + self._ready = False + self._registered = False + self._server = None + self._parser = None + + self.register_plugin('xep_0077') # In-band registration + self.register_plugin('xep_0030') + self.register_plugin('xep_0059') + self.register_plugin('xep_0060') # PubSub + + self.add_event_handler("session_start", self.start) + self.add_event_handler("register", self.register) + self.add_event_handler("pubsub_publish", self.handle_omf_message) + + #Init the parser + self._init_parser() + + def _init_parser(self): + """ Init the parser depending on the OMF Version + + """ + self._parser = OMF6Parser() + + @property +
    [docs] def ready(self): + """ Check if the client is ready + + """ + return self._ready +
    +
    [docs] def start(self, event): + """ Send presence to the Xmppp Server. This function is called directly by the sleekXmpp library + + """ + self.send_presence() + self._ready = True + self._server = "pubsub.%s" % self.boundjid.domain +
    +
    [docs] def register(self, iq): + """ Register to the Xmppp Server. This function is called directly by the sleekXmpp library + + """ + if self._registered: + msg = " %s already registered!" % self.boundjid + self.info(msg) + return + + resp = self.Iq() + resp['type'] = 'set' + resp['register']['username'] = self.boundjid.user + resp['register']['password'] = self.password + + try: + resp.send(now=True) + msg = " Account created for %s!" % self.boundjid + self.info(msg) + self._registered = True + except IqError as e: + msg = " Could not register account: %s" % e.iq['error']['text'] + self.error(msg) + except IqTimeout: + msg = " No response from server." + self.error(msg) +
    +
    [docs] def unregister(self): + """ Unregister from the Xmppp Server. + + """ + try: + self.plugin['xep_0077'].cancel_registration( + ifrom=self.boundjid.full) + msg = " Account unregistered for %s!" % self.boundjid + self.info(msg) + except IqError as e: + msg = " Could not unregister account: %s" % e.iq['error']['text'] + self.error(msg) + except IqTimeout: + msg = " No response from server." + self.error(msg) +
    +
    [docs] def nodes(self): + """ Get all the nodes of the Xmppp Server. + + """ + try: + result = self['xep_0060'].get_nodes(self._server) + for item in result['disco_items']['items']: + msg = ' - %s' % str(item) + self.debug(msg) + return result + except: + error = traceback.format_exc() + msg = 'Could not retrieve node list.\ntraceback:\n%s' % error + self.error(msg) +
    +
    [docs] def subscriptions(self): + """ Get all the subscriptions of the Xmppp Server. + + """ + try: + result = self['xep_0060'].get_subscriptions(self._server) + #self.boundjid.full) + for node in result['node']: + msg = ' - %s' % str(node) + self.debug(msg) + return result + except: + error = traceback.format_exc() + msg = ' Could not retrieve subscriptions.\ntraceback:\n%s' % error + self.error(msg) +
    +
    [docs] def create(self, node): + """ Create the topic corresponding to the node + + :param node: Name of the topic, corresponding to the node (ex : omf.plexus.wlab17) + :type node: str + + """ + msg = " Create Topic : " + node + self.info(msg) + + config = self['xep_0004'].makeForm('submit') + config.add_field(var='pubsub#node_type', value='leaf') + config.add_field(var='pubsub#notify_retract', value='0') + config.add_field(var='pubsub#publish_model', value='open') + config.add_field(var='pubsub#persist_items', value='1') + config.add_field(var='pubsub#max_items', value='1') + config.add_field(var='pubsub#title', value=node) + + try: + self['xep_0060'].create_node(self._server, node, config = config) + except: + #error = traceback.format_exc() + #msg = ' Could not create topic: %s\ntraceback:\n%s' % (node, error) + msg = 'Could not create the topic : '+node+' . Maybe the topic already exists' + self.error(msg) +
    +
    [docs] def delete(self, node): + """ Delete the topic corresponding to the node + + :param node: Name of the topic, corresponding to the node (ex : omf.plexus.wlab17) + :type node: str + + """ + # To check if the queue are well empty at the end + #print " length of the queue : " + str(self.send_queue.qsize()) + #print " length of the queue : " + str(self.event_queue.qsize()) + try: + self['xep_0060'].delete_node(self._server, node) + msg = ' Deleted node: %s' % node + self.info(msg) + except: + #error = traceback.format_exc() + #msg = ' Could not delete topic: %s\ntraceback:\n%s' % (node, error) + msg = 'Could not delete the topic : '+node+' . Maybe It is not the owner of the topic' + self.error(msg) +
    +
    [docs] def publish(self, data, node): + """ Publish the data to the corresponding topic + + :param data: Data that will be published + :type data: str + :param node: Name of the topic + :type node: str + + """ + + msg = " Publish to Topic : " + node + self.info(msg) + try: + result = self['xep_0060'].publish(self._server,node,payload=data) + # id = result['pubsub']['publish']['item']['id'] + # print('Published at item id: %s' % id) + except: + error = traceback.format_exc() + msg = ' Could not publish to: %s\ntraceback:\n%s' % (node, error) + self.error(msg) +
    +
    [docs] def get(self, data): + """ Get the item + + :param data: data from which the items will be get back + :type data: str + + + """ + try: + result = self['xep_0060'].get_item(self._server, self.boundjid, + data) + for item in result['pubsub']['items']['substanzas']: + msg = 'Retrieved item %s: %s' % (item['id'], tostring(item['payload'])) + self.debug(msg) + except: + error = traceback.format_exc() + msg = ' Could not retrieve item %s from topic %s\ntraceback:\n%s' \ + % (data, self.boundjid, error) + self.error(msg) +
    +
    [docs] def retract(self, data): + """ Retract the item + + :param data: data from which the item will be retracted + :type data: str + + """ + try: + result = self['xep_0060'].retract(self._server, self.boundjid, data) + msg = ' Retracted item %s from topic %s' % (data, self.boundjid) + self.debug(msg) + except: + error = traceback.format_exc() + msg = 'Could not retract item %s from topic %s\ntraceback:\n%s' \ + % (data, self.boundjid, error) + self.error(msg) +
    +
    [docs] def purge(self): + """ Purge the information in the server + + """ + try: + result = self['xep_0060'].purge(self._server, self.boundjid) + msg = ' Purged all items from topic %s' % self.boundjid + self.debug(msg) + except: + error = traceback.format_exc() + msg = ' Could not purge items from topic %s\ntraceback:\n%s' \ + % (self.boundjid, error) + self.error(msg) +
    +
    [docs] def subscribe(self, node): + """ Subscribe to a topic + + :param node: Name of the topic + :type node: str + + """ + try: + result = self['xep_0060'].subscribe(self._server, node) + msg = ' Subscribed %s to topic %s' \ + % (self.boundjid.user, node) + #self.info(msg) + self.debug(msg) + except: + error = traceback.format_exc() + msg = ' Could not subscribe %s to topic %s\ntraceback:\n%s' \ + % (self.boundjid.bare, node, error) + self.error(msg) +
    +
    [docs] def unsubscribe(self, node): + """ Unsubscribe to a topic + + :param node: Name of the topic + :type node: str + + """ + try: + result = self['xep_0060'].unsubscribe(self._server, node) + msg = ' Unsubscribed %s from topic %s' % (self.boundjid.bare, node) + self.debug(msg) + except: + error = traceback.format_exc() + msg = ' Could not unsubscribe %s from topic %s\ntraceback:\n%s' \ + % (self.boundjid.bare, node, error) + self.error(msg) +
    +
    [docs] def check_mailbox(self, itype, attr): + """ Check the mail box + + :param itype: type of mail + :type itype: str + :param attr: value wanted + :type attr: str + + """ + return self._parser.check_mailbox(itype, attr) + +
    +
    [docs] def handle_omf_message(self, iq): + """ Handle published/received message + + :param iq: Stanzas that is currently published/received + :type iq: Iq Stanza + + """ + self._parser.handle(iq) +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_resource.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_resource.html new file mode 100644 index 00000000..d88f1218 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_resource.html @@ -0,0 +1,167 @@ + + + + + + + + nepi.resources.omf.omf_resource — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.omf_resource

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Julien Tribino <julien.tribino@inria.fr>
    +#         Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +
    +
    +
    [docs]class ResourceGateway: + """ + Dictionary used to set OMF gateway depending on Testbed information. + """ + #XXX: A.Q. COMMENT: This looks a bit hardcoded + # SHOULDN'T THIS BE IN A SEPARATED FILE RATHER THAN IN THE + # BASE CLASS FOR ALL OMF RESOURCES? + TestbedtoGateway = dict({ + "wilabt" : "ops.wilab2.ilabt.iminds.be", + "nitos" : "nitlab.inf.uth.gr", + "nicta" : "??.??.??", + }) + + AMtoGateway = dict({ + "am.wilab2.ilabt.iminds.be" : "ops.wilab2.ilabt.iminds.be", + "nitlab.inf.uth.gr" : "nitlab.inf.uth.gr", + "nicta" : "??.??.??", + }) +
    +@clsinit_copy +
    [docs]class OMFResource(ResourceManager): + """ + Generic resource gathering XMPP credential information and common methods + for OMF nodes, channels, applications, etc. + """ + _rtype = "abstract::omf::Resource" + _platform = "omf" + + @classmethod + def _register_attributes(cls): + + xmppServer = Attribute("xmppServer", "Xmpp Server", + flags = Flags.Credential) + xmppUser = Attribute("xmppUser","Name of the Xmpp User/Slice", + flags = Flags.Credential) + xmppPort = Attribute("xmppPort", "Xmpp Port", + flags = Flags.Credential) + xmppPassword = Attribute("xmppPassword", "Xmpp Password", + flags = Flags.Credential) + version = Attribute("version", "Version of OMF : Either 5 or 6", + default = "6", ) + + cls._register_attribute(xmppUser) + cls._register_attribute(xmppServer) + cls._register_attribute(xmppPort) + cls._register_attribute(xmppPassword) + cls._register_attribute(version) + + def __init__(self, ec, guid): + super(OMFResource, self).__init__(ec, guid) + pass +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/wilabt_node.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/wilabt_node.html new file mode 100644 index 00000000..ff95e487 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/wilabt_node.html @@ -0,0 +1,559 @@ + + + + + + + + nepi.resources.omf.wilabt_node — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.omf.wilabt_node

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState 
    +from nepi.resources.omf.node import OMFNode
    +from nepi.util.sfaapi import SFAAPIFactory 
    +from nepi.util.execfuncs import lexec
    +from nepi.util import sshfuncs
    +
    +from random import randint
    +import time
    +import re
    +import weakref
    +import socket
    +import threading
    +import datetime
    +
    +@clsinit_copy
    +
    [docs]class WilabtSfaNode(OMFNode): + _rtype = "wilabt::sfa::Node" + _help = "Controls a Wilabt host accessible using a SSH key " \ + "and provisioned using SFA" + _platform = "omf" + + @classmethod + def _register_attributes(cls): + + username = Attribute("username", "Local account username", + flags = Flags.Credential) + + identity = Attribute("identity", "SSH identity file", + flags = Flags.Credential) + + server_key = Attribute("serverKey", "Server public key", + flags = Flags.Design) + + sfa_user = Attribute("sfauser", "SFA user", + flags = Flags.Credential) + + sfa_private_key = Attribute("sfaPrivateKey", "SFA path to the private key \ + used to generate the user credential", + flags = Flags.Credential) + + slicename = Attribute("slicename", "SFA slice for the experiment", + flags = Flags.Credential) + + gateway_user = Attribute("gatewayUser", "Gateway account username", + flags = Flags.Design) + + gateway = Attribute("gateway", "Hostname of the gateway machine", + flags = Flags.Design) + + host = Attribute("host", "Name of the physical machine", + flags = Flags.Design) + + disk_image = Attribute("disk_image", "Specify a specific disk image for a node", + flags = Flags.Design) + + cls._register_attribute(username) + cls._register_attribute(identity) + cls._register_attribute(server_key) + cls._register_attribute(sfa_user) + cls._register_attribute(sfa_private_key) + cls._register_attribute(slicename) + cls._register_attribute(gateway_user) + cls._register_attribute(gateway) + cls._register_attribute(host) + cls._register_attribute(disk_image) + + def __init__(self, ec, guid): + super(WilabtSfaNode, self).__init__(ec, guid) + + self._ecobj = weakref.ref(ec) + self._sfaapi = None + self._node_to_provision = None + self._slicenode = False + self._host = False + self._username = None + + def _skip_provision(self): + sfa_user = self.get("sfauser") + if not sfa_user: + return True + else: return False + + @property +
    [docs] def sfaapi(self): + """ + Property to instanciate the SFA API based in sfi client. + For each SFA method called this instance is used. + """ + if not self._sfaapi: + sfa_user = self.get("sfauser") + sfa_sm = "http://www.wilab2.ilabt.iminds.be:12369/protogeni/xmlrpc/am/3.0" + sfa_auth = '.'.join(sfa_user.split('.')[:2]) + sfa_registry = "http://sfa3.planet-lab.eu:12345/" + sfa_private_key = self.get("sfaPrivateKey") + batch = True + + _sfaapi = SFAAPIFactory.get_api(sfa_user, sfa_auth, + sfa_registry, sfa_sm, sfa_private_key, self._ecobj(), batch, WilabtSfaNode._rtype) + + if not _sfaapi: + self.fail_sfaapi() + + self._sfaapi = weakref.ref(_sfaapi) + + return self._sfaapi() +
    +
    [docs] def do_discover(self): + """ + Based on the attributes defined by the user, discover the suitable + node for provision. + """ + nodes = self.sfaapi.get_resources_hrn() + + host = self._get_host() + if host: + # the user specified one particular node to be provisioned + self._host = True + host_hrn = nodes[host] + + # check that the node is not blacklisted or being provisioned + # by other RM + if not self._blacklisted(host_hrn): + if not self._reserved(host_hrn): + if self._check_if_in_slice([host_hrn]): + self.debug("Node already in slice %s" % host_hrn) + self._slicenode = True + host = host + '.wilab2.ilabt.iminds.be' + self.set('host', host) + self._node_to_provision = host_hrn + super(WilabtSfaNode, self).do_discover() +
    +
    [docs] def do_provision(self): + """ + Add node to user's slice and verifing that the node is functioning + correctly. Check ssh, omf rc running, hostname, file system. + """ + provision_ok = False + ssh_ok = False + proc_ok = False + timeout = 300 + + while not provision_ok: + node = self._node_to_provision + #if self._slicenode: + # self._delete_from_slice() + # self.debug("Waiting 480 sec for re-adding to slice") + # time.sleep(480) # Timout for the testbed to allow a new reservation + self._add_node_to_slice(node) + t = 0 + while not self._check_if_in_slice([node]) and t < timeout \ + and not self._ecobj().abort: + t = t + 5 + time.sleep(t) + self.debug("Waiting 5 sec for resources to be added") + continue + + if not self._check_if_in_slice([node]): + self.debug("Couldn't add node %s to slice" % node) + self.fail_node_not_available(node) + + self._get_username() + ssh_ok = self._check_ssh_loop() + + if not ssh_ok: + # the timeout was reach without establishing ssh connection + # the node is blacklisted, and a new + # node to provision is discovered + self._blacklist_node(node) + self.do_discover() + continue + + # check /proc directory is mounted (ssh_ok = True) + # file system is not read only, hostname is correct + # and omf_rc process is up + else: + if not self._check_fs(): + self.do_discover() + continue + if not self._check_omfrc(): + self.do_discover() + continue + if not self._check_hostname(): + self.do_discover() + continue + + else: + provision_ok = True + if not self.get('host'): + self._set_host_attr(node) + self.info(" Node provisioned ") + + super(WilabtSfaNode, self).do_provision() +
    +
    [docs] def do_deploy(self): + if self.state == ResourceState.NEW: + self.info("Deploying w-iLab.t node") + self.do_discover() + self.do_provision() + super(WilabtSfaNode, self).do_deploy() +
    +
    [docs] def do_release(self): + super(WilabtSfaNode, self).do_release() + if self.state == ResourceState.RELEASED and not self._skip_provision(): + self.debug(" Releasing SFA API ") + self.sfaapi.release() +
    + def _blacklisted(self, host_hrn): + """ + Check in the SFA API that the node is not in the blacklist. + """ + if self.sfaapi.blacklisted(host_hrn): + self.fail_node_not_available(host_hrn) + return False + + def _reserved(self, host_hrn): + """ + Check in the SFA API that the node is not in the reserved + list. + """ + if self.sfaapi.reserved(host_hrn): + self.fail_node_not_available(host_hrn) + return False + + def _get_username(self): + """ + Get the username for login in to the nodes from RSpec. + Wilabt username is not made out of any convention, it + has to be retrived from the manifest RSpec. + """ + slicename = self.get("slicename") + if self._username is None: + slice_info = self.sfaapi.get_slice_resources(slicename) + username = slice_info['resource'][0]['services'][0]['login'][0]['username'] + self.set('username', username) + self.debug("Retriving username information from RSpec %s" % username) + self._username = username + + def _check_ssh_loop(self): + """ + Check that the ssh login is possible. In wilabt is done + through the gateway because is private testbed. + """ + t = 0 + timeout = 1200 + ssh_ok = False + while t < timeout and not ssh_ok: + cmd = 'echo \'GOOD NODE\'' + ((out, err), proc) = self.execute(cmd) + if out.find("GOOD NODE") < 0: + self.debug( "No SSH connection, waiting 20s" ) + t = t + 20 + time.sleep(20) + continue + else: + self.debug( "SSH OK" ) + ssh_ok = True + continue + return ssh_ok + + def _check_fs(self): + """ + Check file system, /proc well mounted. + """ + cmd = 'mount |grep proc' + ((out, err), proc) = self.execute(cmd) + if out.find("/proc type proc") < 0: + self.warning(" Corrupted file system ") + self._blacklist_node(node) + return False + return True + + def _check_omfrc(self): + """ + Check that OMF 6 resource controller is running. + """ + cmd = 'ps aux|grep omf' + ((out, err), proc) = self.execute(cmd) + if out.find("/usr/local/rvm/gems/ruby-1.9.3-p286@omf/bin/omf_rc") < 0: + return False + return True + + def _check_hostname(self): + """ + Check that the hostname in the image is not set to localhost. + """ + cmd = 'hostname' + ((out, err), proc) = self.execute(cmd) + if 'localhost' in out.lower(): + return False + else: + self.set('hostname', out.strip()) + return True + +
    [docs] def execute(self, command, + sudo = False, + env = None, + tty = False, + forward_x11 = False, + retry = 3, + connect_timeout = 30, + strict_host_checking = False, + persistent = True, + blocking = True, + ): + """ Notice that this invocation will block until the + execution finishes. If this is not the desired behavior, + use 'run' instead.""" + (out, err), proc = sshfuncs.rexec( + command, + host = self.get("host"), + user = self.get("username"), + port = 22, + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + sudo = sudo, + identity = self.get("identity"), + server_key = self.get("serverKey"), + env = env, + tty = tty, + forward_x11 = forward_x11, + retry = retry, + connect_timeout = connect_timeout, + persistent = persistent, + blocking = blocking, + strict_host_checking = strict_host_checking + ) + + return (out, err), proc + +
    + def _add_node_to_slice(self, host_hrn): + """ + Add node to slice, using SFA API. Actually Wilabt testbed + doesn't allow adding nodes, in fact in the API there is method + to group all the nodes instanciated as WilabtSfaNodes and the + Allocate and Provision is done with the last call at + sfaapi.add_resource_to_slice_batch. + """ + self.info(" Adding node to slice ") + slicename = self.get("slicename") + disk_image = self.get("disk_image") + if disk_image is not None: + properties = {'disk_image': disk_image} + else: properties = None + #properties = None + self.sfaapi.add_resource_to_slice_batch(slicename, host_hrn, properties=properties) + + def _delete_from_slice(self): + """ + Delete every node from slice, using SFA API. + Wilabt doesn't allow to remove one sliver so this method + remove every slice from the slice. + """ + + self.warning(" Deleting all slivers from slice ") + slicename = self.get("slicename") + self.sfaapi.remove_all_from_slice(slicename) + + def _get_host(self): + """ + Get the attribute hostname. + """ + host = self.get("host") + if host: + return host + else: + return None + + def _set_host_attr(self, node): + """ + Query SFAAPI for the hostname of a certain host hrn and sets the + attribute hostname, it will over write the previous value. + """ + hosts_hrn = self.sfaapi.get_resources_hrn() + for host, hrn in hosts_hrn.iteritems(): + if hrn == node: + host = host + '.wilab2.ilabt.iminds.be' + self.set("host", host) + + def _check_if_in_slice(self, hosts_hrn): + """ + Check using SFA API if any host hrn from hosts_hrn is in the user's + slice. + """ + slicename = self.get("slicename") + slice_nodes = self.sfaapi.get_slice_resources(slicename)['resource'] + if slice_nodes: + if len(slice_nodes[0]['services']) != 0: + slice_nodes_hrn = self.sfaapi.get_resources_hrn(slice_nodes).values() + else: slice_nodes_hrn = [] + nodes_inslice = list(set(hosts_hrn) & set(slice_nodes_hrn)) + return nodes_inslice + + def _blacklist_node(self, host_hrn): + """ + Add mal functioning node to blacklist (in SFA API). + """ + self.warning(" Blacklisting malfunctioning node ") + self.sfaapi.blacklist_resource(host_hrn) + if not self._host: + self.set('host', None) + else: + self.set('host', host_hrn.split('.').pop()) + + def _put_node_in_provision(self, host_hrn): + """ + Add node to the list of nodes being provisioned, in order for other RMs + to not try to provision the same one again. + """ + self.sfaapi.reserve_resource(host_hrn) + + def _get_ip(self, host): + """ + Query cache for the IP of a node with certain hostname + """ + try: + ip = sshfuncs.gethostbyname(host) + except: + # Fail while trying to find the IP + return None + return ip + +
    [docs] def fail_discovery(self): + msg = "Discovery failed. No candidates found for node" + self.error(msg) + raise RuntimeError, msg +
    +
    [docs] def fail_node_not_alive(self, host=None): + msg = "Node %s not alive" % host + raise RuntimeError, msg +
    +
    [docs] def fail_node_not_available(self, host): + msg = "Some nodes not available for provisioning" + raise RuntimeError, msg +
    +
    [docs] def fail_not_enough_nodes(self): + msg = "Not enough nodes available for provisioning" + raise RuntimeError, msg +
    +
    [docs] def fail_sfaapi(self): + msg = "Failing while trying to instanciate the SFA API." + raise RuntimeError, msg +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/node.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/node.html new file mode 100644 index 00000000..7b867949 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/node.html @@ -0,0 +1,775 @@ + + + + + + + + nepi.resources.planetlab.node — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.planetlab.node

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState 
    +from nepi.resources.linux.node import LinuxNode
    +from nepi.resources.planetlab.plcapi import PLCAPIFactory 
    +from nepi.util.execfuncs import lexec
    +from nepi.util import sshfuncs
    +
    +from random import randint
    +import re
    +import os
    +import time
    +import socket
    +import threading
    +import datetime
    +import weakref
    +
    +@clsinit_copy
    +
    [docs]class PlanetlabNode(LinuxNode): + _rtype = "planetlab::Node" + _help = "Controls a PlanetLab host accessible using a SSH key " \ + "associated to a PlanetLab user account" + _platform = "planetlab" + + lock = threading.Lock() + + @classmethod + def _register_attributes(cls): + ip = Attribute("ip", "PlanetLab host public IP address", + flags = Flags.Design) + + pl_url = Attribute("plcApiUrl", "URL of PlanetLab PLCAPI host \ + (e.g. www.planet-lab.eu or www.planet-lab.org) ", + default = "www.planet-lab.eu", + flags = Flags.Credential) + + pl_ptn = Attribute("plcApiPattern", "PLC API service regexp pattern \ + (e.g. https://%(hostname)s:443/PLCAPI/ ) ", + default = "https://%(hostname)s:443/PLCAPI/", + flags = Flags.Design) + + pl_user = Attribute("pluser", "PlanetLab account user, as the one to \ + authenticate in the website) ", + flags = Flags.Credential) + + pl_password = Attribute("plpassword", + "PlanetLab account password, as \ + the one to authenticate in the website) ", + flags = Flags.Credential) + + city = Attribute("city", "Constrain location (city) during resource \ + discovery. May use wildcards.", + flags = Flags.Filter) + + country = Attribute("country", "Constrain location (country) during \ + resource discovery. May use wildcards.", + flags = Flags.Filter) + + region = Attribute("region", "Constrain location (region) during \ + resource discovery. May use wildcards.", + flags = Flags.Filter) + + architecture = Attribute("architecture", "Constrain architecture \ + during resource discovery.", + type = Types.Enumerate, + allowed = ["x86_64", + "i386"], + flags = Flags.Filter) + + operating_system = Attribute("operatingSystem", "Constrain operating \ + system during resource discovery.", + type = Types.Enumerate, + allowed = ["f8", + "f12", + "f14", + "centos", + "other"], + flags = Flags.Filter) + + min_reliability = Attribute("minReliability", "Constrain reliability \ + while picking PlanetLab nodes. Specifies a lower \ + acceptable bound.", + type = Types.Double, + range = (1, 100), + flags = Flags.Filter) + + max_reliability = Attribute("maxReliability", "Constrain reliability \ + while picking PlanetLab nodes. Specifies an upper \ + acceptable bound.", + type = Types.Double, + range = (1, 100), + flags = Flags.Filter) + + min_bandwidth = Attribute("minBandwidth", "Constrain available \ + bandwidth while picking PlanetLab nodes. \ + Specifies a lower acceptable bound.", + type = Types.Double, + range = (0, 2**31), + flags = Flags.Filter) + + max_bandwidth = Attribute("maxBandwidth", "Constrain available \ + bandwidth while picking PlanetLab nodes. \ + Specifies an upper acceptable bound.", + type = Types.Double, + range = (0, 2**31), + flags = Flags.Filter) + + min_load = Attribute("minLoad", "Constrain node load average while \ + picking PlanetLab nodes. Specifies a lower acceptable \ + bound.", + type = Types.Double, + range = (0, 2**31), + flags = Flags.Filter) + + max_load = Attribute("maxLoad", "Constrain node load average while \ + picking PlanetLab nodes. Specifies an upper acceptable \ + bound.", + type = Types.Double, + range = (0, 2**31), + flags = Flags.Filter) + + min_cpu = Attribute("minCpu", "Constrain available cpu time while \ + picking PlanetLab nodes. Specifies a lower acceptable \ + bound.", + type = Types.Double, + range = (0, 100), + flags = Flags.Filter) + + max_cpu = Attribute("maxCpu", "Constrain available cpu time while \ + picking PlanetLab nodes. Specifies an upper acceptable \ + bound.", + type = Types.Double, + range = (0, 100), + flags = Flags.Filter) + + timeframe = Attribute("timeframe", "Past time period in which to check\ + information about the node. Values are year,month, \ + week, latest", + default = "week", + type = Types.Enumerate, + allowed = ["latest", + "week", + "month", + "year"], + flags = Flags.Filter) + + plblacklist = Attribute("persist_blacklist", "Take into account the file plblacklist \ + in the user's home directory under .nepi directory. This file \ + contains a list of PL nodes to blacklist, and at the end \ + of the experiment execution the new blacklisted nodes are added.", + type = Types.Bool, + default = False, + flags = Flags.Global) + + cls._register_attribute(ip) + cls._register_attribute(pl_url) + cls._register_attribute(pl_ptn) + cls._register_attribute(pl_user) + cls._register_attribute(pl_password) + cls._register_attribute(city) + cls._register_attribute(country) + cls._register_attribute(region) + cls._register_attribute(architecture) + cls._register_attribute(operating_system) + cls._register_attribute(min_reliability) + cls._register_attribute(max_reliability) + cls._register_attribute(min_bandwidth) + cls._register_attribute(max_bandwidth) + cls._register_attribute(min_load) + cls._register_attribute(max_load) + cls._register_attribute(min_cpu) + cls._register_attribute(max_cpu) + cls._register_attribute(timeframe) + cls._register_attribute(plblacklist) + + def __init__(self, ec, guid): + super(PlanetlabNode, self).__init__(ec, guid) + + self._ecobj = weakref.ref(ec) + self._plapi = None + self._node_to_provision = None + self._slicenode = False + self._hostname = False + + if self.get("gateway") or self.get("gatewayUser"): + self.set("gateway", None) + self.set("gatewayUser", None) + + # Blacklist file + nepi_home = os.path.join(os.path.expanduser("~"), ".nepi") + plblacklist_file = os.path.join(nepi_home, "plblacklist.txt") + if not os.path.exists(plblacklist_file): + if os.path.isdir(nepi_home): + open(plblacklist_file, 'w').close() + else: + os.makedirs(nepi_home) + open(plblacklist_file, 'w').close() + + def _skip_provision(self): + pl_user = self.get("pluser") + pl_pass = self.get("plpassword") + if not pl_user and not pl_pass: + return True + else: return False + + @property +
    [docs] def plapi(self): + if not self._plapi: + pl_user = self.get("pluser") + pl_pass = self.get("plpassword") + pl_url = self.get("plcApiUrl") + pl_ptn = self.get("plcApiPattern") + _plapi = PLCAPIFactory.get_api(pl_user, pl_pass, pl_url, + pl_ptn, self._ecobj()) + + if not _plapi: + self.fail_plapi() + + self._plapi = weakref.ref(_plapi) + + return self._plapi() +
    +
    [docs] def do_discover(self): + """ + Based on the attributes defined by the user, discover the suitable + nodes for provision. + """ + if self._skip_provision(): + super(PlanetlabNode, self).do_discover() + return + + hostname = self._get_hostname() + if hostname: + # the user specified one particular node to be provisioned + self._hostname = True + node_id = self._get_nodes_id({'hostname':hostname}) + node_id = node_id.pop()['node_id'] + + # check that the node is not blacklisted or being provisioned + # by other RM + with PlanetlabNode.lock: + plist = self.plapi.reserved() + blist = self.plapi.blacklisted() + if node_id not in blist and node_id not in plist: + + # check that is really alive, by performing ping + ping_ok = self._do_ping(node_id) + if not ping_ok: + self._blacklist_node(node_id) + self.fail_node_not_alive(hostname) + else: + if self._check_if_in_slice([node_id]): + self._slicenode = True + self._put_node_in_provision(node_id) + self._node_to_provision = node_id + else: + self.fail_node_not_available(hostname) + super(PlanetlabNode, self).do_discover() + + else: + # the user specifies constraints based on attributes, zero, one or + # more nodes can match these constraints + nodes = self._filter_based_on_attributes() + + # nodes that are already part of user's slice have the priority to + # provisioned + nodes_inslice = self._check_if_in_slice(nodes) + nodes_not_inslice = list(set(nodes) - set(nodes_inslice)) + + node_id = None + if nodes_inslice: + node_id = self._choose_random_node(nodes_inslice) + self._slicenode = True + + if not node_id: + # Either there were no matching nodes in the user's slice, or + # the nodes in the slice were blacklisted or being provisioned + # by other RM. Note nodes_not_inslice is never empty + node_id = self._choose_random_node(nodes_not_inslice) + self._slicenode = False + + if node_id: + self._node_to_provision = node_id + try: + self._set_hostname_attr(node_id) + self.info(" Selected node to provision ") + super(PlanetlabNode, self).do_discover() + except: + with PlanetlabNode.lock: + self._blacklist_node(node_id) + self.do_discover() + else: + self.fail_not_enough_nodes() +
    +
    [docs] def do_provision(self): + """ + Add node to user's slice after verifing that the node is functioning + correctly + """ + if self._skip_provision(): + super(PlanetlabNode, self).do_provision() + return + + provision_ok = False + ssh_ok = False + proc_ok = False + timeout = 1800 + + while not provision_ok: + node = self._node_to_provision + if not self._slicenode: + self._add_node_to_slice(node) + if self._check_if_in_slice([node]): + self.debug( "Node added to slice" ) + else: + self.warning(" Could not add to slice ") + with PlanetlabNode.lock: + self._blacklist_node(node) + self.do_discover() + continue + + # check ssh connection + t = 0 + while t < timeout and not ssh_ok: + + cmd = 'echo \'GOOD NODE\'' + ((out, err), proc) = self.execute(cmd) + if out.find("GOOD NODE") < 0: + self.debug( "No SSH connection, waiting 60s" ) + t = t + 60 + time.sleep(60) + continue + else: + self.debug( "SSH OK" ) + ssh_ok = True + continue + else: + cmd = 'echo \'GOOD NODE\'' + ((out, err), proc) = self.execute(cmd) + if not out.find("GOOD NODE") < 0: + ssh_ok = True + + if not ssh_ok: + # the timeout was reach without establishing ssh connection + # the node is blacklisted, deleted from the slice, and a new + # node to provision is discovered + with PlanetlabNode.lock: + self.warning(" Could not SSH login ") + self._blacklist_node(node) + #self._delete_node_from_slice(node) + self.do_discover() + continue + + # check /proc directory is mounted (ssh_ok = True) + # and file system is not read only + else: + cmd = 'mount |grep proc' + ((out1, err1), proc1) = self.execute(cmd) + cmd = 'touch /tmp/tmpfile; rm /tmp/tmpfile' + ((out2, err2), proc2) = self.execute(cmd) + if out1.find("/proc type proc") < 0 or \ + "Read-only file system".lower() in err2.lower(): + with PlanetlabNode.lock: + self.warning(" Corrupted file system ") + self._blacklist_node(node) + #self._delete_node_from_slice(node) + self.do_discover() + continue + + else: + provision_ok = True + if not self.get('hostname'): + self._set_hostname_attr(node) + # set IP attribute + ip = self._get_ip(node) + self.set("ip", ip) + self.info(" Node provisioned ") + + super(PlanetlabNode, self).do_provision() +
    +
    [docs] def do_release(self): + super(PlanetlabNode, self).do_release() + if self.state == ResourceState.RELEASED and not self._skip_provision(): + self.debug(" Releasing PLC API ") + self.plapi.release() +
    + def _filter_based_on_attributes(self): + """ + Retrive the list of nodes ids that match user's constraints + """ + # Map user's defined attributes with tagnames of PlanetLab + timeframe = self.get("timeframe")[0] + attr_to_tags = { + 'city' : 'city', + 'country' : 'country', + 'region' : 'region', + 'architecture' : 'arch', + 'operatingSystem' : 'fcdistro', + 'minReliability' : 'reliability%s' % timeframe, + 'maxReliability' : 'reliability%s' % timeframe, + 'minBandwidth' : 'bw%s' % timeframe, + 'maxBandwidth' : 'bw%s' % timeframe, + 'minLoad' : 'load%s' % timeframe, + 'maxLoad' : 'load%s' % timeframe, + 'minCpu' : 'cpu%s' % timeframe, + 'maxCpu' : 'cpu%s' % timeframe, + } + + nodes_id = [] + filters = {} + + for attr_name, attr_obj in self._attrs.iteritems(): + attr_value = self.get(attr_name) + + if attr_value is not None and attr_obj.has_flag(Flags.Filter) and \ + attr_name != 'timeframe': + + attr_tag = attr_to_tags[attr_name] + filters['tagname'] = attr_tag + + # filter nodes by fixed constraints e.g. operating system + if not 'min' in attr_name and not 'max' in attr_name: + filters['value'] = attr_value + nodes_id = self._filter_by_fixed_attr(filters, nodes_id) + + # filter nodes by range constraints e.g. max bandwidth + elif ('min' or 'max') in attr_name: + nodes_id = self._filter_by_range_attr(attr_name, attr_value, filters, nodes_id) + + if not filters: + nodes = self._get_nodes_id() + for node in nodes: + nodes_id.append(node['node_id']) + return nodes_id + + def _filter_by_fixed_attr(self, filters, nodes_id): + """ + Query PLCAPI for nodes ids matching fixed attributes defined by the + user + """ + node_tags = self.plapi.get_node_tags(filters) + if node_tags is not None: + + if len(nodes_id) == 0: + # first attribute being matched + for node_tag in node_tags: + nodes_id.append(node_tag['node_id']) + else: + # remove the nodes ids that don't match the new attribute + # that is being match + + nodes_id_tmp = [] + for node_tag in node_tags: + if node_tag['node_id'] in nodes_id: + nodes_id_tmp.append(node_tag['node_id']) + + if len(nodes_id_tmp): + nodes_id = set(nodes_id) & set(nodes_id_tmp) + else: + # no node from before match the new constraint + self.fail_discovery() + else: + # no nodes match the filter applied + self.fail_discovery() + + return nodes_id + + def _filter_by_range_attr(self, attr_name, attr_value, filters, nodes_id): + """ + Query PLCAPI for nodes ids matching attributes defined in a certain + range, by the user + """ + node_tags = self.plapi.get_node_tags(filters) + if node_tags: + + if len(nodes_id) == 0: + # first attribute being matched + for node_tag in node_tags: + + # check that matches the min or max restriction + if 'min' in attr_name and node_tag['value'] != 'n/a' and \ + float(node_tag['value']) > attr_value: + nodes_id.append(node_tag['node_id']) + + elif 'max' in attr_name and node_tag['value'] != 'n/a' and \ + float(node_tag['value']) < attr_value: + nodes_id.append(node_tag['node_id']) + else: + + # remove the nodes ids that don't match the new attribute + # that is being match + nodes_id_tmp = [] + for node_tag in node_tags: + + # check that matches the min or max restriction and was a + # matching previous filters + if 'min' in attr_name and node_tag['value'] != 'n/a' and \ + float(node_tag['value']) > attr_value and \ + node_tag['node_id'] in nodes_id: + nodes_id_tmp.append(node_tag['node_id']) + + elif 'max' in attr_name and node_tag['value'] != 'n/a' and \ + float(node_tag['value']) < attr_value and \ + node_tag['node_id'] in nodes_id: + nodes_id_tmp.append(node_tag['node_id']) + + if len(nodes_id_tmp): + nodes_id = set(nodes_id) & set(nodes_id_tmp) + else: + # no node from before match the new constraint + self.fail_discovery() + + else: #TODO CHECK + # no nodes match the filter applied + self.fail_discovery() + + return nodes_id + + def _choose_random_node(self, nodes): + """ + From the possible nodes for provision, choose randomly to decrese the + probability of different RMs choosing the same node for provision + """ + size = len(nodes) + while size: + size = size - 1 + index = randint(0, size) + node_id = nodes[index] + nodes[index] = nodes[size] + + # check the node is not blacklisted or being provision by other RM + # and perform ping to check that is really alive + with PlanetlabNode.lock: + + blist = self.plapi.blacklisted() + plist = self.plapi.reserved() + if node_id not in blist and node_id not in plist: + ping_ok = self._do_ping(node_id) + if not ping_ok: + self._set_hostname_attr(node_id) + self.warning(" Node not responding PING ") + self._blacklist_node(node_id) + else: + # discovered node for provision, added to provision list + self._put_node_in_provision(node_id) + return node_id + + def _get_nodes_id(self, filters=None): + return self.plapi.get_nodes(filters, fields=['node_id']) + + def _add_node_to_slice(self, node_id): + self.info(" Adding node to slice ") + slicename = self.get("username") + with PlanetlabNode.lock: + slice_nodes = self.plapi.get_slice_nodes(slicename) + self.debug(" Previous slice nodes %s " % slice_nodes) + slice_nodes.append(node_id) + self.plapi.add_slice_nodes(slicename, slice_nodes) + + def _delete_node_from_slice(self, node): + self.warning(" Deleting node from slice ") + slicename = self.get("username") + self.plapi.delete_slice_node(slicename, [node]) + + def _get_hostname(self): + hostname = self.get("hostname") + if hostname: + return hostname + ip = self.get("ip") + if ip: + hostname = socket.gethostbyaddr(ip)[0] + self.set('hostname', hostname) + return hostname + else: + return None + + def _set_hostname_attr(self, node): + """ + Query PLCAPI for the hostname of a certain node id and sets the + attribute hostname, it will over write the previous value + """ + hostname = self.plapi.get_nodes(node, ['hostname']) + self.set("hostname", hostname[0]['hostname']) + + def _check_if_in_slice(self, nodes_id): + """ + Query PLCAPI to find out if any node id from nodes_id is in the user's + slice + """ + slicename = self.get("username") + slice_nodes = self.plapi.get_slice_nodes(slicename) + nodes_inslice = list(set(nodes_id) & set(slice_nodes)) + return nodes_inslice + + def _do_ping(self, node_id): + """ + Perform ping command on node's IP matching node id + """ + ping_ok = False + ip = self._get_ip(node_id) + if ip: + command = "ping -c4 %s" % ip + (out, err) = lexec(command) + + m = re.search("(\d+)% packet loss", str(out)) + if m and int(m.groups()[0]) < 50: + ping_ok = True + + return ping_ok + + def _blacklist_node(self, node): + """ + Add node mal functioning node to blacklist + """ + self.warning(" Blacklisting malfunctioning node ") + self.plapi.blacklist_host(node) + if not self._hostname: + self.set('hostname', None) + + def _put_node_in_provision(self, node): + """ + Add node to the list of nodes being provisioned, in order for other RMs + to not try to provision the same one again + """ + self.plapi.reserve_host(node) + + def _get_ip(self, node_id): + """ + Query PLCAPI for the IP of a node with certain node id + """ + hostname = self.get("hostname") or \ + self.plapi.get_nodes(node_id, ['hostname'])[0]['hostname'] + try: + ip = sshfuncs.gethostbyname(hostname) + except: + # Fail while trying to find the IP + return None + return ip + +
    [docs] def fail_discovery(self): + msg = "Discovery failed. No candidates found for node" + self.error(msg) + raise RuntimeError, msg +
    +
    [docs] def fail_node_not_alive(self, hostname=None): + msg = "Node %s not alive" % hostname + raise RuntimeError, msg +
    +
    [docs] def fail_node_not_available(self, hostname): + msg = "Node %s not available for provisioning" % hostname + raise RuntimeError, msg +
    +
    [docs] def fail_not_enough_nodes(self): + msg = "Not enough nodes available for provisioning" + raise RuntimeError, msg +
    +
    [docs] def fail_plapi(self): + msg = "Failing while trying to instanciate the PLC API.\nSet the" + \ + " attributes pluser and plpassword." + raise RuntimeError, msg +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/fdudptunnel.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/fdudptunnel.html new file mode 100644 index 00000000..a0543e36 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/fdudptunnel.html @@ -0,0 +1,164 @@ + + + + + + + + nepi.resources.planetlab.ns3.fdudptunnel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.planetlab.ns3.fdudptunnel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState
    +from nepi.resources.linux.ns3.fdudptunnel import LinuxNs3FdUdpTunnel
    +from nepi.util.sshfuncs import ProcStatus
    +from nepi.util.timefuncs import tnow, tdiffsec
    +
    +import base64
    +import os
    +import socket
    +import time
    +
    +@clsinit_copy
    +
    [docs]class PlanetlabNs3FdUdpTunnel(LinuxNs3FdUdpTunnel): + _rtype = "planetlab::ns3::FdUdpTunnel" + _help = "Constructs a tunnel between two Ns-3 FdNetdevices " \ + "located in remote PlanetLab nodes using a UDP connection " + _platform = "planetlab::ns3" + +
    [docs] def get_endpoints(self): + """ Returns the list of RM that are endpoints to the tunnel + """ + if not self._fd2 or not self._fd1: + from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice + devices = self.get_connected(NS3BaseFdNetDevice.get_rtype()) + if not devices or len(devices) != 2: + msg = "Tunnel must be connected to exactly two FdNetDevices" + self.error(msg) + raise RuntimeError, msg + + self._fd1 = devices[0] + self._fd2 = devices[1] + self._pi = True + + # Set PI headers on + self._fd1.set("EncapsulationMode", "DixPi") + self._fd2.set("EncapsulationMode", "DixPi") + + simu = self._fd1.simulation + from nepi.resources.linux.node import LinuxNode + nodes = simu.get_connected(LinuxNode.get_rtype()) + self._fd1node = nodes[0] + + simu = self._fd2.simulation + from nepi.resources.linux.node import LinuxNode + nodes = simu.get_connected(LinuxNode.get_rtype()) + self._fd2node = nodes[0] + + if self._fd1node.get("hostname") == \ + self._fd2node.get("hostname"): + msg = "Tunnel requires endpoints on different hosts" + self.error(msg) + raise RuntimeError, msg + + return [self._fd1, self._fd2] +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/tuntapfdlink.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/tuntapfdlink.html new file mode 100644 index 00000000..ffbc91c3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/tuntapfdlink.html @@ -0,0 +1,183 @@ + + + + + + + + nepi.resources.planetlab.ns3.tuntapfdlink — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.planetlab.ns3.tuntapfdlink

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2014 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import ResourceState, clsinit_copy
    +from nepi.resources.linux.ns3.tuntapfdlink import LinuxTunTapFdLink
    +
    +import base64
    +import fcntl
    +import os
    +import socket
    +import struct
    +
    +@clsinit_copy
    +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovs.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovs.html new file mode 100644 index 00000000..a1198604 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovs.html @@ -0,0 +1,406 @@ + + + + + + + + nepi.resources.planetlab.openvswitch.ovs — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.planetlab.openvswitch.ovs

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Authors: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Alexandros Kouvakas <alexandros.kouvakas@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.execution.attribute import Attribute, Flags
    +from nepi.resources.planetlab.node import PlanetlabNode        
    +from nepi.resources.linux.application import LinuxApplication
    +import os
    +
    +@clsinit_copy                    
    +
    [docs]class PlanetlabOVSSwitch(LinuxApplication): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + + _rtype = "planetlab::OVSSwitch" + _help = "Runs an OpenVSwitch on a PlanetLab host" + _platform = "planetlab" + + _authorized_connections = ["planetlab::Node", "planetla::OVSPort", "linux::Node"] + + @classmethod + def _register_attributes(cls): + """ Register the attributes of OVSSwitch RM + + """ + bridge_name = Attribute("bridge_name", + "Name of the switch/bridge", + flags = Flags.Design) + virtual_ip_pref = Attribute("virtual_ip_pref", + "Virtual IP/PREFIX of the switch", + flags = Flags.Design) + controller_ip = Attribute("controller_ip", + "IP of the controller", + flags = Flags.Design) + controller_port = Attribute("controller_port", + "Port of the controller", + flags = Flags.Design) + + cls._register_attribute(bridge_name) + cls._register_attribute(virtual_ip_pref) + cls._register_attribute(controller_ip) + cls._register_attribute(controller_port) + + def __init__(self, ec, guid): + """ + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + super(PlanetlabOVSSwitch, self).__init__(ec, guid) + self._home = "ovsswitch-%s" % self.guid + self._node = None + + @property +
    [docs] def node(self): + """ Node wthat run the switch + """ + if not self._node: + nodes = self.get_connected(PlanetlabNode.get_rtype()) + if not nodes or len(nodes) != 1: + msg = "PlanetlabOVSSwitch must be connected to exactly one PlanetlabNode" + #self.error(msg) + raise RuntimeError, msg + + self._node = nodes[0] + + return self._node +
    +
    [docs] def valid_connection(self, guid): + """ Check if the connection with the guid in parameter is possible. Only meaningful connections are allowed. + + :param guid: Guid of the current RM + :type guid: int + :rtype: Boolean + + """ + rm = self.ec.get_resource(guid) + if rm.get_rtype() not in self._authorized_connections: + return False + return True +
    +
    [docs] def do_provision(self): + self.node.mkdir(self.run_home) + + self.check_sliver_ovs() + self.servers_on() + self.create_bridge() + self.assign_controller() + self.ovs_status() + + self.set_provisioned() +
    +
    [docs] def do_deploy(self): + """ Deploy the OVS Switch : Turn on the server, create the bridges + and assign the controller + """ + + if not self.node or self.node.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def check_sliver_ovs(self): + """ Check if sliver-ovs exists. If it does not exist, the execution is stopped + """ + command = "compgen -c | grep sliver-ovs" + shfile = os.path.join(self.app_home, "check_ovs_cmd.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo = True, + pidfile="check_ovs_cmd_pidfile", + ecodefile="check_ovs_cmd_exitcode", + stdout="check_ovs_cmd_stdout", + stderr="check_ovs_cmd_stderr") + except RuntimeError: + msg = "Command sliver-ovs does not exist on the VM" + self.debug(msg) + raise RuntimeError, msg +
    +
    [docs] def servers_on(self): + """ Start the openvswitch servers and check it + """ + # Make sure the server is not running + command = "sliver-ovs del-bridge %s; sliver-ovs stop" % self.get('bridge_name') + shfile = os.path.join(self.app_home, "clean.sh") + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + raise_on_error=False, + pidfile="clean_pidfile", + ecodefile="clean_exitcode", + stdout="clean_stdout", + stderr="clean_stderr") + + # start the server + command = "sliver-ovs start" + shfile = os.path.join(self.app_home, "start.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="start_pidfile", + ecodefile="start_exitcode", + stdout="start_stdout", + stderr="start_stderr") + except RuntimeError: + msg = "Failed to start ovs-server on VM" + self.debug(msg) + raise RuntimeError, msg + + command = "ps -A | grep ovsdb-server" + shfile = os.path.join(self.app_home, "ovsdb_status.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="ovsdb_status_pidfile", + ecodefile="ovsdb_status_exitcode", + stdout="ovsdb_status_stdout", + stderr="ovsdb_status_stderr") + except RuntimeError: + msg = "ovsdb-server not running on VM" + self.debug(msg) + raise RuntimeError, msg + + self.info("Server OVS Started...") +
    +
    [docs] def create_bridge(self): + """ Create the bridge/switch and check error during SSH connection + """ + # TODO: Check if previous bridge exist and delete them. Use ovs-vsctl list-br + # TODO: Add check for virtual_ip belonging to vsys_tag + if not (self.get("bridge_name") and self.get("virtual_ip_pref")): + msg = "No assignment in one or both attributes" + self.error(msg) + raise AttributeError, msg + + command = "sliver-ovs create-bridge '%s' '%s'" % ( + self.get("bridge_name"), + self.get("virtual_ip_pref")) + + shfile = os.path.join(self.app_home, "bridge_create.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="bridge_create_pidfile", + ecodefile="bridge_create_exitcode", + stdout="bridge_create_stdout", + stderr="bridge_create_stderr") + except RuntimeError: + msg = "No such pltap netdev\novs-appctl: ovs-vswitchd: server returned an error" + self.debug(msg) + raise RuntimeError, msg + + self.info(" Bridge %s Created and Assigned to %s" %\ + (self.get("bridge_name"), self.get("virtual_ip_pref")) ) +
    +
    [docs] def assign_controller(self): + """ Set the controller IP + """ + + if not (self.get("controller_ip") and self.get("controller_port")): + return + + """ + if not (self.get("controller_ip") and self.get("controller_port")): + msg = "No assignment in one or both attributes" + self.error(msg) + raise AttributeError, msg + """ + command = "ovs-vsctl set-controller %s tcp:%s:%s" % \ + (self.get("bridge_name"), + self.get("controller_ip"), + self.get("controller_port")) + + shfile = os.path.join(self.app_home, "set_controller.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="set_controller_pidfile", + ecodefile="set_controller_exitcode", + stdout="set_controller_stdout", + stderr="set_controller_stderr") + except RuntimeError: + msg = "SSH connection in the method assign_controller" + self.debug(msg) + raise RuntimeError, msg + + self.info("Controller assigned to the bridge %s" % self.get("bridge_name")) +
    +
    [docs] def ovs_status(self): + """ Print the status of the bridge + """ + command = "sliver-ovs show | tail -n +2" + shfile = os.path.join(self.app_home, "ovs_status.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="ovs_status_pidfile", + ecodefile="ovs_status_exitcode", + stdout="ovs_status_stdout", + stderr="ovs_status_stderr") + except RuntimeError: + msg = "Error when checking the status of the OpenVswitch" + self.debug(msg) + raise RuntimeError, msg +
    +
    [docs] def do_release(self): + """ Delete the bridge and close the server. + + .. note : It need to wait for the others RM (OVSPort and OVSTunnel) + to be released before releasing itself + + """ + + from nepi.resources.planetlab.openvswitch.ovsport import PlanetlabOVSPort + rms = self.get_connected(PlanetlabOVSPort.get_rtype()) + + for rm in rms: + if rm.state < ResourceState.RELEASED: + self.ec.schedule(self.reschedule_delay, self.release) + return + + msg = "Deleting the bridge %s" % self.get('bridge_name') + self.info(msg) + + command = "sliver-ovs del-bridge %s; sliver-ovs stop" % self.get('bridge_name') + shfile = os.path.join(self.app_home, "stop.sh") + + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="stop_pidfile", + ecodefile="stop_exitcode", + stdout="stop_stdout", + stderr="stop_stderr") + + super(PlanetlabOVSSwitch, self).do_release() +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovsport.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovsport.html new file mode 100644 index 00000000..3ef19467 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovsport.html @@ -0,0 +1,384 @@ + + + + + + + + nepi.resources.planetlab.openvswitch.ovsport — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.planetlab.openvswitch.ovsport

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Authors: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Alexandros Kouvakas <alexandros.kouvakas@inria.fr>
    +#         Julien Tribino <julien.tribino@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.planetlab.openvswitch.ovs import PlanetlabOVSSwitch        
    +from nepi.resources.planetlab.node import PlanetlabNode        
    +from nepi.resources.linux.application import LinuxApplication
    +
    +import os
    +
    +@clsinit_copy                 
    +
    [docs]class PlanetlabOVSPort(LinuxApplication): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + + _rtype = "planetlab::OVSPort" + _help = "Runs an OpenVSwitch on a PlanetLab host" + _platform = "planetlab" + + _authorized_connections = ["planetlab::OVSSwitch", "linux::UdpTunnel", "linux::Tunnel"] + + @classmethod + def _register_attributes(cls): + """ Register the attributes of OVSPort RM + + """ + port_name = Attribute("port_name", "Name of the port", + flags = Flags.Design) + ip = Attribute("ip", "IP of the endpoint. This is the attribute " + "you should use to establish a tunnel or a remote " + "connection between endpoint", + flags = Flags.Design) + network = Attribute("network", "Network used by the port", + flags = Flags.Design) + + cls._register_attribute(port_name) + cls._register_attribute(ip) + cls._register_attribute(network) + + def __init__(self, ec, guid): + """ + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + super(PlanetlabOVSPort, self).__init__(ec, guid) + self._home = "ovsport-%s" % self.guid + self._port_number = None + + @property +
    [docs] def node(self): + """ Node that run the switch and the ports + """ + return self.ovsswitch.node +
    + @property +
    [docs] def ovsswitch(self): + """ Switch where the port is created + """ + ovsswitch = self.get_connected(PlanetlabOVSSwitch.get_rtype()) + if ovsswitch: return ovsswitch[0] + return None +
    + @property +
    [docs] def port_number(self): + return self._port_number +
    +
    [docs] def valid_connection(self, guid): + """ Check if the connection is available. + + :param guid: Guid of the current RM + :type guid: int + :rtype: Boolean + + """ + rm = self.ec.get_resource(guid) + if rm.get_rtype() not in self._authorized_connections: + return False + + return True +
    +
    [docs] def create_port(self): + """ Create the desired port + """ + msg = "Creating the port %s" % self.get('port_name') + self.debug(msg) + + if not self.get('port_name'): + msg = "The port name is not assigned" + self.error(msg) + raise AttributeError, msg + + if not self.ovsswitch: + msg = "The OVSwitch RM is not running" + self.error(msg) + raise AttributeError, msg + + command = "sliver-ovs create-port %s %s" % ( + self.ovsswitch.get('bridge_name'), + self.get('port_name')) + + shfile = os.path.join(self.app_home, "create_port.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo = True, + stderr="port_stdout", + stdout="port_stderr", + pidfile="port_pidfile", + ecodefile="port_exitcode") + except RuntimeError: + msg = "Could not create ovs-port" + self.debug(msg) + raise RuntimeError, msg + + self.info("Created port %s on switch %s" % ( + self.get('port_name'), + self.ovsswitch.get('bridge_name'))) +
    +
    [docs] def initiate_udp_connection(self, remote_endpoint, connection_app_home, + connection_run_home, cipher, cipher_key, bwlimit, txqueuelen): + """ Get the local_endpoint of the port + """ + msg = "Discovering the port number for %s" % self.get('port_name') + self.info(msg) + + command = "sliver-ovs get-local-endpoint %s" % self.get('port_name') + + shfile = os.path.join(connection_app_home, "get_port.sh") + (out, err), proc = self.node.run_and_wait(command, connection_run_home, + shfile=shfile, + sudo=True, + overwrite = True, + pidfile="get_port_pidfile", + ecodefile="get_port_exitcode", + stdout="get_port_stdout", + stderr="get_port_stderr") + + if err != "": + msg = "Error retrieving the local endpoint of the port" + self.error(msg) + raise RuntimeError, msg + + if out: + self._port_number = out.strip() + + self.info("The number of the %s is %s" % (self.get('port_name'), + self.port_number)) + + # Must set a routing rule in the ovs client nodes so they know + # that the LAN can be found through the switch + if remote_endpoint.is_rm_instance("planetlab::Tap"): + self._vroute = self.ec.register_resource("planetlab::Vroute") + self.ec.set(self._vroute, "action", "add") + self.ec.set(self._vroute, "prefix", remote_endpoint.get("prefix")) + self.ec.set(self._vroute, "nexthop", remote_endpoint.get("pointopoint")) + self.ec.set(self._vroute, "network", self.get("network")) + + self.ec.register_connection(self._vroute, remote_endpoint.guid) + self.ec.deploy(guids=[self._vroute], group = self.deployment_group) + + # For debugging + msg = "Route for the tap configured" + self.debug(msg) + + return self.port_number +
    +
    [docs] def establish_udp_connection(self, remote_endpoint, + connection_app_home, + connection_run_home, + port): + remote_ip = remote_endpoint.node.get("ip") + command = self._establish_connection_command(port, remote_ip) + + shfile = os.path.join(connection_app_home, "connect_port.sh") + (out, err), proc = self.node.run_and_wait(command, connection_run_home, + shfile=shfile, + sudo=True, + overwrite = True, + pidfile="connect_port_pidfile", + ecodefile="connect_port_exitcode", + stdout="connect_port_stdout", + stderr="connect_port_stderr") + + # For debugging + msg = "Connection on port configured" + self.debug(msg) +
    + def _establish_connection_command(self, port, remote_ip): + """ Script to create the connection from a switch to a + remote endpoint + """ + local_port_name = self.get('port_name') + + command = ["sliver-ovs"] + command.append("set-remote-endpoint") + command.append(local_port_name) + command.append(remote_ip) + command.append(port) + command = " ".join(command) + command = self.replace_paths(command) + return command + +
    [docs] def verify_connection(self, remote_endpoint, connection_app_home, + connection_run_home): + self.ovsswitch.ovs_status() +
    +
    [docs] def terminate_connection(self, endpoint, connection_app_home, + connection_run_home): + return True +
    +
    [docs] def check_status(self): + return self.node.status(self._pid, self._ppid) +
    +
    [docs] def do_provision(self): + self.node.mkdir(self.run_home) + + self.create_port() + end_ip = self.ovsswitch.get('virtual_ip_pref').split('/') + self.set("ip", end_ip[0]) + + #Check the status of the OVS Switch + self.ovsswitch.ovs_status() + + self.set_provisioned() +
    +
    [docs] def do_deploy(self): + """ Deploy the OVS port after the OVS Switch + """ + if not self.ovsswitch or self.ovsswitch.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- OVSwitch state %s " % self.ovsswitch.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + self.do_discover() + self.do_provision() + + self.set_ready() +
    +
    [docs] def do_release(self): + """ Delete the port on the OVSwitch. It needs to wait for the tunnel + to be released. + """ + from nepi.resources.linux.udptunnel import LinuxUdpTunnel + rm = self.get_connected(LinuxUdpTunnel.get_rtype()) + + if rm and rm[0].state < ResourceState.STOPPED: + self.ec.schedule(self.reschedule_delay, self.release) + return + + msg = "Deleting the port %s" % self.get('port_name') + self.info(msg) + + command = "sliver-ovs del_port %s" % self.get('port_name') + + shfile = os.path.join(self.app_home, "stop.sh") + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="stop_pidfile", + ecodefile="stop_exitcode", + stdout="stop_stdout", + stderr="stop_stderr") + + super(PlanetlabOVSPort, self).do_release() +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/plcapi.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/plcapi.html new file mode 100644 index 00000000..0a560cba --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/plcapi.html @@ -0,0 +1,676 @@ + + + + + + + + nepi.resources.planetlab.plcapi — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.planetlab.plcapi

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import functools
    +import hashlib
    +import socket
    +import os
    +import time
    +import threading
    +import xmlrpclib
    +
    +def _retry(fn):
    +    def rv(*p, **kw):
    +        for x in xrange(5):
    +            try:
    +                return fn(*p, **kw)
    +            except (socket.error, IOError, OSError):
    +                time.sleep(x*5+5)
    +        else:
    +            return fn (*p, **kw)
    +    return rv
    +
    +
    [docs]class PLCAPI(object): + + _expected_methods = set( + ['AddNodeTag', 'AddConfFile', 'DeletePersonTag', 'AddNodeType', + 'DeleteBootState', 'SliceListNames', 'DeleteKey','SliceGetTicket', + 'SliceUsersList', 'SliceUpdate', 'GetNodeGroups', 'SliceCreate', + 'GetNetworkMethods', 'GetNodeFlavour', 'DeleteNode', 'BootNotifyOwners', + 'AddPersonKey', 'AddNode', 'UpdateNodeGroup', 'GetAddressTypes', + 'AddIlink', 'DeleteNetworkType', 'GetInitScripts', 'GenerateNodeConfFile', + 'AddSite', 'BindObjectToPeer', 'SliceListUserSlices', 'GetPeers', + 'AddPeer', 'DeletePeer', 'AddRole', 'DeleteRole', 'SetPersonPrimarySite', + 'AddSiteAddress', 'SliceDelete', 'NotifyPersons', 'GetKeyTypes', + 'GetConfFiles', 'GetIlinks', 'AddTagType', 'GetNodes', 'DeleteNodeTag', + 'DeleteSliceFromNodesWhitelist', 'UpdateAddress', 'ResetPassword', + 'AddSliceToNodesWhitelist', 'AddRoleToTagType', 'AddLeases', + 'GetAddresses', 'AddInitScript', 'RebootNode', 'GetPCUTypes', + 'RefreshPeer', 'GetBootMedium', 'UpdateKey', 'UpdatePCU', 'GetSession', + 'AddInterfaceTag', 'UpdatePCUType', 'GetInterfaces', 'SliceExtendedInfo', + 'SliceNodesList', 'DeleteRoleFromTagType', 'DeleteSlice', 'GetSites', + 'DeleteMessage', 'GetSliceFamily', 'GetPlcRelease', 'UpdateTagType', + 'AddSliceInstantiation', 'ResolveSlices', 'GetSlices', + 'DeleteRoleFromPerson', 'GetSessions', 'UpdatePeer', 'VerifyPerson', + 'GetPersonTags', 'DeleteKeyType', 'AddSlice', 'SliceUserAdd', + 'DeleteSession', 'GetMessages', 'DeletePCU', 'GetPeerData', + 'DeletePersonFromSite', 'DeleteTagType', 'GetPCUs', 'UpdateLeases', + 'AddMessage', 'DeletePCUProtocolType', 'DeleteInterfaceTag', + 'AddPersonToSite', 'GetSlivers', 'SliceNodesDel', + 'DeleteAddressTypeFromAddress', 'AddNodeGroup', 'GetSliceTags', + 'DeleteSite', 'GetSiteTags', 'UpdateMessage', 'DeleteSliceFromNodes', + 'SliceRenew', 'UpdatePCUProtocolType', 'DeleteSiteTag', + 'GetPCUProtocolTypes', 'GetEvents', 'GetSliceTicket', 'AddPersonTag', + 'BootGetNodeDetails', 'DeleteInterface', 'DeleteNodeGroup', + 'AddPCUProtocolType', 'BootCheckAuthentication', 'AddSiteTag', + 'AddAddressTypeToAddress', 'DeleteConfFile', 'DeleteInitScript', + 'DeletePerson', 'DeleteIlink', 'DeleteAddressType', 'AddBootState', + 'AuthCheck', 'NotifySupport', 'GetSliceInstantiations', 'AddPCUType', + 'AddPCU', 'AddSession', 'GetEventObjects', 'UpdateSiteTag', + 'UpdateNodeTag', 'AddPerson', 'BlacklistKey', 'UpdateInitScript', + 'AddSliceToNodes', 'RebootNodeWithPCU', 'GetNodeTags', 'GetSliceKeys', + 'GetSliceSshKeys', 'AddNetworkMethod', 'SliceNodesAdd', + 'DeletePersonFromSlice', 'ReportRunlevel', 'GetNetworkTypes', + 'UpdateSite', 'DeleteConfFileFromNodeGroup', 'UpdateNode', + 'DeleteSliceInstantiation', 'DeleteSliceTag', 'BootUpdateNode', + 'UpdatePerson', 'UpdateConfFile', 'SliceUserDel', 'DeleteLeases', + 'AddConfFileToNodeGroup', 'UpdatePersonTag', 'DeleteConfFileFromNode', + 'AddPersonToSlice', 'UnBindObjectFromPeer', 'AddNodeToPCU', + 'GetLeaseGranularity', 'DeletePCUType', 'GetTagTypes', 'GetNodeTypes', + 'UpdateInterfaceTag', 'GetRoles', 'UpdateSlice', 'UpdateSliceTag', + 'AddSliceTag', 'AddNetworkType', 'AddInterface', 'AddAddressType', + 'AddRoleToPerson', 'DeleteNodeType', 'GetLeases', 'UpdateInterface', + 'SliceInfo', 'DeleteAddress', 'SliceTicketGet', 'GetPersons', + 'GetWhitelist', 'AddKeyType', 'UpdateAddressType', 'GetPeerName', + 'DeleteNetworkMethod', 'UpdateIlink', 'AddConfFileToNode', 'GetKeys', + 'DeleteNodeFromPCU', 'GetInterfaceTags', 'GetBootStates', + 'SetInterfaceSens', 'SetNodeLoadm', 'GetInterfaceRate', 'GetNodeLoadw', + 'SetInterfaceKey', 'GetNodeSlices', 'GetNodeLoadm', 'SetSliceVref', + 'GetInterfaceIwpriv', 'SetNodeLoadw', 'SetNodeSerial', + 'GetNodePlainBootstrapfs', 'SetNodeMEMw', 'GetNodeResponse', + 'SetInterfaceRate', 'SetSliceInitscript', 'SetNodeFcdistro', + 'GetNodeLoady', 'SetNodeArch', 'SetNodeKargs', 'SetNodeMEMm', + 'SetNodeBWy', 'SetNodeBWw', 'SetInterfaceSecurityMode', 'SetNodeBWm', + 'SetNodeASType', 'GetNodeKargs', 'GetPersonColumnconf', + 'GetNodeResponsem', 'GetNodeCPUy', 'GetNodeCramfs', 'SetNodeSlicesw', + 'SetPersonColumnconf', 'SetNodeSlicesy', 'GetNodeCPUw', 'GetNodeBWy', + 'GetNodeCPUm', 'GetInterfaceDriver', 'GetNodeLoad', 'GetInterfaceMode', + 'GetNodeSerial', 'SetNodeSlicesm', 'SetNodeLoady', 'GetNodeReliabilityw', + 'SetSliceFcdistro', 'GetNodeReliabilityy', 'SetInterfaceEssid', + 'SetSliceInitscriptCode', 'GetNodeExtensions', 'GetSliceOmfControl', + 'SetNodeCity', 'SetInterfaceIfname', 'SetNodeHrn', 'SetNodeNoHangcheck', + 'GetNodeNoHangcheck', 'GetSliceFcdistro', 'SetNodeCountry', + 'SetNodeKvariant', 'GetNodeKvariant', 'GetNodeMEMy', 'SetInterfaceIwpriv', + 'GetNodeMEMw', 'SetInterfaceBackdoor', 'GetInterfaceFreq', + 'SetInterfaceChannel', 'SetInterfaceNw', 'GetPersonShowconf', + 'GetSliceInitscriptCode', 'SetNodeMEM', 'GetInterfaceEssid', 'GetNodeMEMm', + 'SetInterfaceMode', 'SetInterfaceIwconfig', 'GetNodeSlicesm', 'GetNodeBWm', + 'SetNodePlainBootstrapfs', 'SetNodeRegion', 'SetNodeCPU', 'GetNodeSlicesw', + 'SetNodeBW', 'SetNodeSlices', 'SetNodeCramfs', 'GetNodeSlicesy', + 'GetInterfaceKey', 'GetSliceInitscript', 'SetNodeCPUm', 'SetSliceArch', + 'SetNodeLoad', 'SetNodeResponse', 'GetSliceSliverHMAC', 'GetNodeBWw', + 'GetNodeRegion', 'SetNodeMEMy', 'GetNodeASType', 'SetNodePldistro', + 'GetSliceArch', 'GetNodeCountry', 'SetSliceOmfControl', 'GetNodeHrn', + 'GetNodeCity', 'SetInterfaceAlias', 'GetNodeBW', 'GetNodePldistro', + 'GetSlicePldistro', 'SetNodeASNumber', 'GetSliceHmac', 'SetSliceHmac', + 'GetNodeMEM', 'GetNodeASNumber', 'GetInterfaceAlias', 'GetSliceVref', + 'GetNodeArch', 'GetSliceSshKey', 'GetInterfaceKey4', 'GetInterfaceKey2', + 'GetInterfaceKey3', 'GetInterfaceKey1', 'GetInterfaceBackdoor', + 'GetInterfaceIfname', 'SetSliceSliverHMAC', 'SetNodeReliability', + 'GetNodeCPU', 'SetPersonShowconf', 'SetNodeExtensions', 'SetNodeCPUy', + 'SetNodeCPUw', 'GetNodeResponsew', 'SetNodeResponsey', 'GetInterfaceSens', + 'SetNodeResponsew', 'GetNodeResponsey', 'GetNodeReliability', + 'GetNodeReliabilitym', 'SetNodeResponsem', 'SetInterfaceDriver', + 'GetInterfaceSecurityMode', 'SetNodeDeployment', 'SetNodeReliabilitym', + 'GetNodeFcdistro', 'SetInterfaceFreq', 'GetInterfaceNw', + 'SetNodeReliabilityy', 'SetNodeReliabilityw', 'GetInterfaceIwconfig', + 'SetSlicePldistro', 'SetSliceSshKey', 'GetNodeDeployment', + 'GetInterfaceChannel', 'SetInterfaceKey2', 'SetInterfaceKey3', + 'SetInterfaceKey1', 'SetInterfaceKey4']) + + _required_methods = set() + + def __init__(self, username, password, hostname, urlpattern, ec, proxy, session_key = None, + local_peer = "PLE"): + + self._blacklist = set() + self._reserved = set() + self._nodes_cache = None + self._already_cached = False + self._ecobj = ec + self.count = 1 + + if session_key is not None: + self.auth = dict(AuthMethod='session', session=session_key) + elif username is not None and password is not None: + self.auth = dict(AuthMethod='password', Username=username, AuthString=password) + else: + self.auth = dict(AuthMethod='anonymous') + + self._local_peer = local_peer + self._url = urlpattern % {'hostname':hostname} + + if (proxy is not None): + import urllib2 + class HTTPSProxyTransport(xmlrpclib.Transport): + def __init__(self, proxy, use_datetime=0): + opener = urllib2.build_opener(urllib2.ProxyHandler({"https" : proxy})) + xmlrpclib.Transport.__init__(self, use_datetime) + self.opener = opener + + def request(self, host, handler, request_body, verbose=0): + req = urllib2.Request('https://%s%s' % (host, handler), request_body) + req.add_header('User-agent', self.user_agent) + self.verbose = verbose + return self.parse_response(self.opener.open(req)) + + self._proxy_transport = lambda : HTTPSProxyTransport(proxy) + else: + self._proxy_transport = lambda : None + + self.threadlocal = threading.local() + + # Load blacklist from file + if self._ecobj.get_global('planetlab::Node', 'persist_blacklist'): + self._set_blacklist() + + @property +
    [docs] def api(self): + # Cannot reuse same proxy in all threads, py2.7 is not threadsafe + return xmlrpclib.ServerProxy( + self._url , + transport = self._proxy_transport(), + allow_none = True) +
    + @property +
    [docs] def mcapi(self): + try: + return self.threadlocal.mc + except AttributeError: + return self.api +
    +
    [docs] def test(self): + # TODO: Use nepi utils Logger instead of warning!! + import warnings + + # validate XMLRPC server checking supported API calls + methods = set(_retry(self.mcapi.system.listMethods)()) + if self._required_methods - methods: + warnings.warn("Unsupported REQUIRED methods: %s" % ( + ", ".join(sorted(self._required_methods - methods)), ) ) + return False + + if self._expected_methods - methods: + warnings.warn("Unsupported EXPECTED methods: %s" % ( + ", ".join(sorted(self._expected_methods - methods)), ) ) + + try: + # test authorization + network_types = _retry(self.mcapi.GetNetworkTypes)(self.auth) + except (xmlrpclib.ProtocolError, xmlrpclib.Fault),e: + warnings.warn(str(e)) + + return True +
    + def _set_blacklist(self): + nepi_home = os.path.join(os.path.expanduser("~"), ".nepi") + plblacklist_file = os.path.join(nepi_home, "plblacklist.txt") + with open(plblacklist_file, 'r') as f: + hosts_tobl = f.read().splitlines() + if hosts_tobl: + nodes_id = self.get_nodes(hosts_tobl, ['node_id']) + for node_id in nodes_id: + self._blacklist.add(node_id['node_id']) + + @property +
    [docs] def network_types(self): + try: + return self._network_types + except AttributeError: + self._network_types = _retry(self.mcapi.GetNetworkTypes)(self.auth) + return self._network_types +
    + @property +
    [docs] def peer_map(self): + try: + return self._peer_map + except AttributeError: + peers = _retry(self.mcapi.GetPeers)(self.auth, {}, ['shortname','peername','peer_id']) + + self._peer_map = dict( + (peer['shortname'], peer['peer_id']) + for peer in peers + ) + + self._peer_map.update( + (peer['peername'], peer['peer_id']) + for peer in peers + ) + + self._peer_map.update( + (peer['peer_id'], peer['shortname']) + for peer in peers + ) + + self._peer_map[None] = self._local_peer + return self._peer_map +
    +
    [docs] def get_node_flavour(self, node): + """ + Returns detailed information on a given node's flavour, + i.e. its base installation. + + This depends on the global PLC settings in the PLC_FLAVOUR area, + optionnally overridden by any of the following tags if set on that node: + 'arch', 'pldistro', 'fcdistro', 'deployment', 'extensions' + + Params: + + * node : int or string + - int, Node identifier + - string, Fully qualified hostname + + Returns: + + struct + * extensions : array of string, extensions to add to the base install + * fcdistro : string, the fcdistro this node should be based upon + * nodefamily : string, the nodefamily this node should be based upon + * plain : boolean, use plain bootstrapfs image if set (for tests) + """ + if not isinstance(node, (str, int, long)): + raise ValueError, "Node must be either a non-unicode string or an int" + return _retry(self.mcapi.GetNodeFlavour)(self.auth, node) +
    +
    [docs] def get_nodes(self, node_id_or_name = None, fields = None, **kw): + """ + Returns an array of structs containing details about nodes. + If node_id_or_name is specified and is an array of node identifiers + or hostnames, or the filters keyword argument with struct of node + attributes, or node attributes by keyword argument, + only nodes matching the filter will be returned. + + If fields is specified, only the specified details will be returned. + NOTE that if fields is unspecified, the complete set of native fields are + returned, which DOES NOT include tags at this time. + + Some fields may only be viewed by admins. + + Special params: + + fields: an optional list of fields to retrieve. The default is all. + + filters: an optional mapping with custom filters, which is the only + way to support complex filters like negation and numeric comparisons. + + peer: a string (or sequence of strings) with the name(s) of peers + to filter - or None for local nodes. + """ + if fields is not None: + fieldstuple = (fields,) + else: + fieldstuple = () + + if node_id_or_name is not None: + return _retry(self.mcapi.GetNodes)(self.auth, node_id_or_name, *fieldstuple) + else: + filters = kw.pop('filters',{}) + + if 'peer' in kw: + peer = kw.pop('peer') + + name_to_id = self.peer_map.get + + if hasattr(peer, '__iter__'): + # we can't mix local and external nodes, so + # split and re-issue recursively in that case + if None in peer or self._local_peer in peer: + if None in peer: + peer.remove(None) + + if self._local_peer in peer: + peer.remove(self._local_peer) + + return ( + self.get_nodes(node_id_or_name, fields, + filters = filters, peer=peer, **kw) + \ + self.get_nodes(node_id_or_name, fields, + filters = filters, peer=None, **kw) + ) + else: + peer_filter = map(name_to_id, peer) + + elif peer is None or peer == self._local_peer: + peer_filter = None + else: + peer_filter = name_to_id(peer) + + filters['peer_id'] = peer_filter + + filters.update(kw) + + if not filters and not fieldstuple: + if not self._nodes_cache and not self._already_cached: + self._already_cached = True + self._nodes_cache = _retry(self.mcapi.GetNodes)(self.auth) + elif not self._nodes_cache: + while not self._nodes_cache: + time.sleep(10) + return self._nodes_cache + + return _retry(self.mcapi.GetNodes)(self.auth, filters, *fieldstuple) +
    +
    [docs] def get_node_tags(self, node_tag_id = None, fields = None, **kw): + if fields is not None: + fieldstuple = (fields,) + else: + fieldstuple = () + + if node_tag_id is not None: + return _retry(self.mcapi.GetNodeTags)(self.auth, node_tag_id, + *fieldstuple) + else: + filters = kw.pop('filters',{}) + filters.update(kw) + return _retry(self.mcapi.GetNodeTags)(self.auth, filters, + *fieldstuple) +
    +
    [docs] def get_slice_tags(self, slice_tag_id = None, fields = None, **kw): + if fields is not None: + fieldstuple = (fields,) + else: + fieldstuple = () + + if slice_tag_id is not None: + return _retry(self.mcapi.GetSliceTags)(self.auth, slice_tag_id, + *fieldstuple) + else: + filters = kw.pop('filters',{}) + filters.update(kw) + return _retry(self.mcapi.GetSliceTags)(self.auth, filters, + *fieldstuple) +
    +
    [docs] def get_interfaces(self, interface_id_or_ip = None, fields = None, **kw): + if fields is not None: + fieldstuple = (fields,) + else: + fieldstuple = () + + if interface_id_or_ip is not None: + return _retry(self.mcapi.GetInterfaces)(self.auth, + interface_id_or_ip, *fieldstuple) + else: + filters = kw.pop('filters',{}) + filters.update(kw) + return _retry(self.mcapi.GetInterfaces)(self.auth, filters, + *fieldstuple) +
    +
    [docs] def get_slices(self, slice_id_or_name = None, fields = None, **kw): + if fields is not None: + fieldstuple = (fields,) + else: + fieldstuple = () + + if slice_id_or_name is not None: + return _retry(self.mcapi.GetSlices)(self.auth, slice_id_or_name, + *fieldstuple) + else: + filters = kw.pop('filters',{}) + filters.update(kw) + return _retry(self.mcapi.GetSlices)(self.auth, filters, + *fieldstuple) +
    +
    [docs] def update_slice(self, slice_id_or_name, **kw): + return _retry(self.mcapi.UpdateSlice)(self.auth, slice_id_or_name, kw) +
    +
    [docs] def delete_slice_node(self, slice_id_or_name, node_id_or_hostname): + return _retry(self.mcapi.DeleteSliceFromNodes)(self.auth, slice_id_or_name, node_id_or_hostname) +
    +
    [docs] def start_multicall(self): + self.threadlocal.mc = xmlrpclib.MultiCall(self.mcapi) +
    +
    [docs] def finish_multicall(self): + mc = self.threadlocal.mc + del self.threadlocal.mc + return _retry(mc)() +
    +
    [docs] def get_slice_nodes(self, slicename): + return self.get_slices(slicename, ['node_ids'])[0]['node_ids'] +
    +
    [docs] def add_slice_nodes(self, slicename, nodes): + self.update_slice(slicename, nodes=nodes) +
    +
    [docs] def get_node_info(self, node_id): + self.start_multicall() + info = self.get_nodes(node_id) + tags = self.get_node_tags(node_id=node_id, fields=('tagname','value')) + info, tags = self.finish_multicall() + return info, tags +
    +
    [docs] def get_slice_id(self, slicename): + slice_id = None + slices = self.get_slices(slicename, fields=('slice_id',)) + if slices: + slice_id = slices[0]['slice_id'] + + # If it wasn't found, don't remember this failure, keep trying + return slice_id +
    +
    [docs] def get_slice_vnet_sys_tag(self, slicename): + slicetags = self.get_slice_tags( + name = slicename, + tagname = 'vsys_vnet', + fields=('value',)) + + if slicetags: + return slicetags[0]['value'] + else: + return None +
    +
    [docs] def blacklist_host(self, node_id): + self._blacklist.add(node_id) +
    +
    [docs] def blacklisted(self): + return self._blacklist +
    +
    [docs] def unblacklist_host(self, node_id): + del self._blacklist[node_id] +
    +
    [docs] def reserve_host(self, node_id): + self._reserved.add(node_id) +
    +
    [docs] def reserved(self): + return self._reserved +
    +
    [docs] def unreserve_host(self, node_id): + del self._reserved[node_id] +
    +
    [docs] def release(self): + self.count -= 1 + if self.count == 0: + blacklist = self._blacklist + self._blacklist = set() + self._reserved = set() + if self._ecobj.get_global('PlanetlabNode', 'persist_blacklist'): + if blacklist: + to_blacklist = list() + hostnames = self.get_nodes(list(blacklist), ['hostname']) + for hostname in hostnames: + to_blacklist.append(hostname['hostname']) + + nepi_home = os.path.join(os.path.expanduser("~"), ".nepi") + plblacklist_file = os.path.join(nepi_home, "plblacklist.txt") + + with open(plblacklist_file, 'w') as f: + for host in to_blacklist: + f.write("%s\n" % host) + +
    +
    [docs]class PLCAPIFactory(object): + """ + .. note:: + + It allows PlanetLab RMs sharing a same slice, to use a same plcapi instance, + and to sincronize blacklisted and reserved hosts. + + """ + # use lock to avoid concurrent access to the Api list at the same times by 2 different threads + _lock = threading.Lock() + _apis = dict() + + @classmethod +
    [docs] def get_api(cls, pl_user, pl_pass, pl_host, + pl_ptn, ec, proxy = None): + """ Get existing PLCAPI instance + + :param pl_user: Planelab user name (used for web login) + :type pl_user: str + :param pl_pass: Planetlab password (used for web login) + :type pl_pass: str + :param pl_host: Planetlab registry host (e.g. "www.planet-lab.eu") + :type pl_host: str + :param pl_ptn: XMLRPC service pattern (e.g. https://%(hostname)s:443/PLCAPI/) + :type pl_ptn: str + :param proxy: Proxy service url + :type pl_ptn: str + """ + if pl_user and pl_pass and pl_host: + key = cls._make_key(pl_user, pl_host) + with cls._lock: + api = cls._apis.get(key) + if not api: + api = cls.create_api(pl_user, pl_pass, pl_host, pl_ptn, ec, proxy) + else: + api.count += 1 + return api + return None +
    + @classmethod +
    [docs] def create_api(cls, pl_user, pl_pass, pl_host, + pl_ptn, ec, proxy = None): + """ Create an PLCAPI instance + + :param pl_user: Planelab user name (used for web login) + :type pl_user: str + :param pl_pass: Planetlab password (used for web login) + :type pl_pass: str + :param pl_host: Planetlab registry host (e.g. "www.planet-lab.eu") + :type pl_host: str + :param pl_ptn: XMLRPC service pattern (e.g. https://%(hostname)s:443/PLCAPI/) + :type pl_ptn: str + :param proxy: Proxy service url + :type pl_ptn: str + """ + api = PLCAPI(username = pl_user, password = pl_pass, hostname = pl_host, + urlpattern = pl_ptn, ec = ec, proxy = proxy) + key = cls._make_key(pl_user, pl_host) + cls._apis[key] = api + return api +
    + @classmethod + def _make_key(cls, *args): + """ Hash the credentials in order to create a key + + :param args: list of arguments used to create the hash (user, host, port, ...) + :type args: list of args + + """ + skey = "".join(map(str, args)) + return hashlib.md5(skey).hexdigest() +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/sfa_node.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/sfa_node.html new file mode 100644 index 00000000..772422c1 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/sfa_node.html @@ -0,0 +1,762 @@ + + + + + + + + nepi.resources.planetlab.sfa_node — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.planetlab.sfa_node

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import ResourceManager, clsinit_copy, \
    +        ResourceState
    +from nepi.resources.linux.node import LinuxNode
    +from nepi.util.sfaapi import SFAAPIFactory 
    +from nepi.util.execfuncs import lexec
    +from nepi.util import sshfuncs
    +
    +from random import randint
    +import re
    +import os
    +import weakref
    +import time
    +import socket
    +import threading
    +import datetime
    +
    +@clsinit_copy
    +
    [docs]class PlanetlabSfaNode(LinuxNode): + _rtype = "planetlab::sfa::Node" + _help = "Controls a PlanetLab host accessible using a SSH key " \ + "and provisioned using SFA" + _platform = "planetlab" + + @classmethod + def _register_attributes(cls): + + sfa_user = Attribute("sfauser", "SFA user", + flags = Flags.Credential) + + sfa_private_key = Attribute("sfaPrivateKey", "SFA path to the private key \ + used to generate the user credential") + + city = Attribute("city", "Constrain location (city) during resource \ + discovery. May use wildcards.", + flags = Flags.Filter) + + country = Attribute("country", "Constrain location (country) during \ + resource discovery. May use wildcards.", + flags = Flags.Filter) + + region = Attribute("region", "Constrain location (region) during \ + resource discovery. May use wildcards.", + flags = Flags.Filter) + + architecture = Attribute("architecture", "Constrain architecture \ + during resource discovery.", + type = Types.Enumerate, + allowed = ["x86_64", + "i386"], + flags = Flags.Filter) + + operating_system = Attribute("operatingSystem", "Constrain operating \ + system during resource discovery.", + type = Types.Enumerate, + allowed = ["f8", + "f12", + "f14", + "centos", + "other"], + flags = Flags.Filter) + + min_reliability = Attribute("minReliability", "Constrain reliability \ + while picking PlanetLab nodes. Specifies a lower \ + acceptable bound.", + type = Types.Double, + range = (1, 100), + flags = Flags.Filter) + + max_reliability = Attribute("maxReliability", "Constrain reliability \ + while picking PlanetLab nodes. Specifies an upper \ + acceptable bound.", + type = Types.Double, + range = (1, 100), + flags = Flags.Filter) + + min_bandwidth = Attribute("minBandwidth", "Constrain available \ + bandwidth while picking PlanetLab nodes. \ + Specifies a lower acceptable bound.", + type = Types.Double, + range = (0, 2**31), + flags = Flags.Filter) + + max_bandwidth = Attribute("maxBandwidth", "Constrain available \ + bandwidth while picking PlanetLab nodes. \ + Specifies an upper acceptable bound.", + type = Types.Double, + range = (0, 2**31), + flags = Flags.Filter) + + min_load = Attribute("minLoad", "Constrain node load average while \ + picking PlanetLab nodes. Specifies a lower acceptable \ + bound.", + type = Types.Double, + range = (0, 2**31), + flags = Flags.Filter) + + max_load = Attribute("maxLoad", "Constrain node load average while \ + picking PlanetLab nodes. Specifies an upper acceptable \ + bound.", + type = Types.Double, + range = (0, 2**31), + flags = Flags.Filter) + + min_cpu = Attribute("minCpu", "Constrain available cpu time while \ + picking PlanetLab nodes. Specifies a lower acceptable \ + bound.", + type = Types.Double, + range = (0, 100), + flags = Flags.Filter) + + max_cpu = Attribute("maxCpu", "Constrain available cpu time while \ + picking PlanetLab nodes. Specifies an upper acceptable \ + bound.", + type = Types.Double, + range = (0, 100), + flags = Flags.Filter) + + timeframe = Attribute("timeframe", "Past time period in which to check\ + information about the node. Values are year,month, \ + week, latest", + default = "week", + type = Types.Enumerate, + allowed = ["latest", + "week", + "month", + "year"], + flags = Flags.Filter) + + plblacklist = Attribute("persist_blacklist", "Take into account the file plblacklist \ + in the user's home directory under .nepi directory. This file \ + contains a list of PL nodes to blacklist, and at the end \ + of the experiment execution the new blacklisted nodes are added.", + type = Types.Bool, + default = False, + flags = Flags.Global) + + cls._register_attribute(sfa_user) + cls._register_attribute(sfa_private_key) + cls._register_attribute(city) + cls._register_attribute(country) + cls._register_attribute(region) + cls._register_attribute(architecture) + cls._register_attribute(operating_system) + cls._register_attribute(min_reliability) + cls._register_attribute(max_reliability) + cls._register_attribute(min_bandwidth) + cls._register_attribute(max_bandwidth) + cls._register_attribute(min_load) + cls._register_attribute(max_load) + cls._register_attribute(min_cpu) + cls._register_attribute(max_cpu) + cls._register_attribute(timeframe) + cls._register_attribute(plblacklist) + + def __init__(self, ec, guid): + super(PlanetlabSfaNode, self).__init__(ec, guid) + + self._ecobj = weakref.ref(ec) + self._sfaapi = None + self._node_to_provision = None + self._slicenode = False + self._hostname = False + + if self.get("gateway") or self.get("gatewayUser"): + self.set("gateway", None) + self.set("gatewayUser", None) + + # Blacklist file for PL nodes + nepi_home = os.path.join(os.path.expanduser("~"), ".nepi") + plblacklist_file = os.path.join(nepi_home, "plblacklist.txt") + if not os.path.exists(plblacklist_file): + if os.path.isdir(nepi_home): + open(plblacklist_file, 'w').close() + else: + os.makedirs(nepi_home) + open(plblacklist_file, 'w').close() + + def _skip_provision(self): + sfa_user = self.get("sfauser") + if not sfa_user: + return True + else: return False + + @property +
    [docs] def sfaapi(self): + """ + Property to instanciate the SFA API based in sfi client. + For each SFA method called this instance is used. + """ + if not self._sfaapi: + sfa_user = self.get("sfauser") + sfa_sm = "http://sfa3.planet-lab.eu:12346/" + sfa_auth = '.'.join(sfa_user.split('.')[:2]) + sfa_registry = "http://sfa3.planet-lab.eu:12345/" + sfa_private_key = self.get("sfaPrivateKey") + + _sfaapi = SFAAPIFactory.get_api(sfa_user, sfa_auth, + sfa_registry, sfa_sm, sfa_private_key, self._ecobj()) + + if not _sfaapi: + self.fail_sfaapi() + + self._sfaapi = weakref.ref(_sfaapi) + + return self._sfaapi() +
    +
    [docs] def do_discover(self): + """ + Based on the attributes defined by the user, discover the suitable + nodes for provision. + """ + if self._skip_provision(): + super(PlanetlabSfaNode, self).do_discover() + return + + nodes = self.sfaapi.get_resources_hrn() + + hostname = self._get_hostname() + if hostname: + # the user specified one particular node to be provisioned + self._hostname = True + host_hrn = nodes[hostname] + + # check that the node is not blacklisted or being provisioned + # by other RM + if not self._blacklisted(host_hrn) and not self._reserved(host_hrn): + # Node in reservation + ping_ok = self._do_ping(hostname) + if not ping_ok: + self._blacklist_node(host_hrn) + self.fail_node_not_alive(hostname) + else: + if self._check_if_in_slice([host_hrn]): + self.debug("The node %s is already in the slice" % hostname) + self._slicenode = True + self._node_to_provision = host_hrn + else: + self.fail_node_not_available(hostname) + super(PlanetlabSfaNode, self).do_discover() + + else: + hosts_hrn = nodes.values() + nodes_inslice = self._check_if_in_slice(hosts_hrn) + nodes_not_inslice = list(set(hosts_hrn) - set(nodes_inslice)) + host_hrn = None + if nodes_inslice: + host_hrn = self._choose_random_node(nodes, nodes_inslice) + self._slicenode = True + + if not host_hrn: + # Either there were no matching nodes in the user's slice, or + # the nodes in the slice were blacklisted or being provisioned + # by other RM. Note nodes_not_inslice is never empty + host_hrn = self._choose_random_node(nodes, nodes_not_inslice) + self._slicenode = False + + if host_hrn: + self._node_to_provision = host_hrn + try: + self._set_hostname_attr(host_hrn) + self.info(" Selected node to provision ") + super(PlanetlabSfaNode, self).do_discover() + except: + self._blacklist_node(host_hrn) + self.do_discover() + else: + self.fail_not_enough_nodes() +
    + def _blacklisted(self, host_hrn): + """ + Check in the SFA API that the node is not in the blacklist. + """ + if self.sfaapi.blacklisted(host_hrn): + return True + return False + + def _reserved(self, host_hrn): + """ + Check in the SFA API that the node is not in the reserved + list. + """ + if self.sfaapi.reserved(host_hrn): + return True + return False + +
    [docs] def do_provision(self): + """ + Add node to user's slice and verifing that the node is functioning + correctly. Check ssh, file system. + """ + if self._skip_provision(): + super(PlanetlabSfaNode, self).do_provision() + return + + provision_ok = False + ssh_ok = False + proc_ok = False + timeout = 1800 + + while not provision_ok: + node = self._node_to_provision + if not self._slicenode: + self._add_node_to_slice(node) + + # check ssh connection + t = 0 + while t < timeout and not ssh_ok: + + cmd = 'echo \'GOOD NODE\'' + ((out, err), proc) = self.execute(cmd) + if out.find("GOOD NODE") < 0: + self.debug( "No SSH connection, waiting 60s" ) + t = t + 60 + time.sleep(60) + continue + else: + self.debug( "SSH OK" ) + ssh_ok = True + continue + else: + cmd = 'echo \'GOOD NODE\'' + ((out, err), proc) = self.execute(cmd) + if not out.find("GOOD NODE") < 0: + ssh_ok = True + + if not ssh_ok: + # the timeout was reach without establishing ssh connection + # the node is blacklisted, deleted from the slice, and a new + # node to provision is discovered + self.warning(" Could not SSH login ") + self._blacklist_node(node) + self.do_discover() + continue + + # check /proc directory is mounted (ssh_ok = True) + # and file system is not read only + else: + cmd = 'mount |grep proc' + ((out1, err1), proc1) = self.execute(cmd) + cmd = 'touch /tmp/tmpfile; rm /tmp/tmpfile' + ((out2, err2), proc2) = self.execute(cmd) + if out1.find("/proc type proc") < 0 or \ + "Read-only file system".lower() in err2.lower(): + self.warning(" Corrupted file system ") + self._blacklist_node(node) + self.do_discover() + continue + + else: + provision_ok = True + if not self.get('hostname'): + self._set_hostname_attr(node) + self.info(" Node provisioned ") + + super(PlanetlabSfaNode, self).do_provision() +
    +
    [docs] def do_release(self): + super(PlanetlabSfaNode, self).do_release() + if self.state == ResourceState.RELEASED and not self._skip_provision(): + self.debug(" Releasing SFA API ") + self.sfaapi.release() + +# def _filter_based_on_attributes(self): +# """ +# Retrive the list of nodes hrn that match user's constraints +# """ +# # Map user's defined attributes with tagnames of PlanetLab +# timeframe = self.get("timeframe")[0] +# attr_to_tags = { +# 'city' : 'city', +# 'country' : 'country', +# 'region' : 'region', +# 'architecture' : 'arch', +# 'operatingSystem' : 'fcdistro', +# 'minReliability' : 'reliability%s' % timeframe, +# 'maxReliability' : 'reliability%s' % timeframe, +# 'minBandwidth' : 'bw%s' % timeframe, +# 'maxBandwidth' : 'bw%s' % timeframe, +# 'minLoad' : 'load%s' % timeframe, +# 'maxLoad' : 'load%s' % timeframe, +# 'minCpu' : 'cpu%s' % timeframe, +# 'maxCpu' : 'cpu%s' % timeframe, +# } +# +# nodes_hrn = [] +# filters = {} +# +# for attr_name, attr_obj in self._attrs.iteritems(): +# attr_value = self.get(attr_name) +# +# if attr_value is not None and attr_obj.has_flag(Flags.Filter) and \ +# attr_name != 'timeframe': +# +# attr_tag = attr_to_tags[attr_name] +# filters['tagname'] = attr_tag +# +# # filter nodes by fixed constraints e.g. operating system +# if not 'min' in attr_name and not 'max' in attr_name: +# filters['value'] = attr_value +# nodes_hrn = self._filter_by_fixed_attr(filters, nodes_hrn) +# +# # filter nodes by range constraints e.g. max bandwidth +# elif ('min' or 'max') in attr_name: +# nodes_hrn = self._filter_by_range_attr(attr_name, attr_value, filters, nodes_hrn) +# +# if not filters: +# nodes = self.sfaapi.get_resources_hrn() +# for node in nodes: +# nodes_hrn.append(node[node.key()]) +# return nodes_hrn +# +# def _filter_by_fixed_attr(self, filters, nodes_hrn): +# """ +# Query SFA API for nodes matching fixed attributes defined by the +# user +# """ +# pass +## node_tags = self.sfaapi.get_resources_tags(filters) +## if node_tags is not None: +## +## if len(nodes_id) == 0: +## # first attribute being matched +## for node_tag in node_tags: +## nodes_id.append(node_tag['node_id']) +## else: +## # remove the nodes ids that don't match the new attribute +## # that is being match +## +## nodes_id_tmp = [] +## for node_tag in node_tags: +## if node_tag['node_id'] in nodes_id: +## nodes_id_tmp.append(node_tag['node_id']) +## +## if len(nodes_id_tmp): +## nodes_id = set(nodes_id) & set(nodes_id_tmp) +## else: +## # no node from before match the new constraint +## self.fail_discovery() +## else: +## # no nodes match the filter applied +## self.fail_discovery() +## +## return nodes_id +# +# def _filter_by_range_attr(self, attr_name, attr_value, filters, nodes_id): +# """ +# Query PLCAPI for nodes ids matching attributes defined in a certain +# range, by the user +# """ +# pass +## node_tags = self.plapi.get_node_tags(filters) +## if node_tags: +## +## if len(nodes_id) == 0: +## # first attribute being matched +## for node_tag in node_tags: +## +## # check that matches the min or max restriction +## if 'min' in attr_name and node_tag['value'] != 'n/a' and \ +## float(node_tag['value']) > attr_value: +## nodes_id.append(node_tag['node_id']) +## +## elif 'max' in attr_name and node_tag['value'] != 'n/a' and \ +## float(node_tag['value']) < attr_value: +## nodes_id.append(node_tag['node_id']) +## else: +## +## # remove the nodes ids that don't match the new attribute +## # that is being match +## nodes_id_tmp = [] +## for node_tag in node_tags: +## +## # check that matches the min or max restriction and was a +## # matching previous filters +## if 'min' in attr_name and node_tag['value'] != 'n/a' and \ +## float(node_tag['value']) > attr_value and \ +## node_tag['node_id'] in nodes_id: +## nodes_id_tmp.append(node_tag['node_id']) +## +## elif 'max' in attr_name and node_tag['value'] != 'n/a' and \ +## float(node_tag['value']) < attr_value and \ +## node_tag['node_id'] in nodes_id: +## nodes_id_tmp.append(node_tag['node_id']) +## +## if len(nodes_id_tmp): +## nodes_id = set(nodes_id) & set(nodes_id_tmp) +## else: +## # no node from before match the new constraint +## self.fail_discovery() +## +## else: #TODO CHECK +## # no nodes match the filter applied +## self.fail_discovery() +## +## return nodes_id +
    + def _choose_random_node(self, nodes, hosts_hrn): + """ + From the possible nodes for provision, choose randomly to decrese the + probability of different RMs choosing the same node for provision + """ + size = len(hosts_hrn) + while size: + size = size - 1 + index = randint(0, size) + host_hrn = hosts_hrn[index] + hosts_hrn[index] = hosts_hrn[size] + + # check the node is not blacklisted or being provision by other RM + # and perform ping to check that is really alive + if not self._blacklisted(host_hrn): + if not self._reserved(host_hrn): + print self.sfaapi._reserved ,self.guid + for hostname, hrn in nodes.iteritems(): + if host_hrn == hrn: + print 'hostname' ,hostname + ping_ok = self._do_ping(hostname) + + if not ping_ok: + self._set_hostname_attr(hostname) + self.warning(" Node not responding PING ") + self._blacklist_node(host_hrn) + else: + # discovered node for provision, added to provision list + self._node_to_provision = host_hrn + return host_hrn + +# def _get_nodes_id(self, filters=None): +# return self.plapi.get_nodes(filters, fields=['node_id']) +# + def _add_node_to_slice(self, host_hrn): + """ + Add node to slice, using SFA API. + """ + self.info(" Adding node to slice ") + slicename = self.get("username").replace('_', '.') + slicename = 'ple.' + slicename + self.sfaapi.add_resource_to_slice(slicename, host_hrn) + + def _delete_from_slice(self): + """ + Delete every node from slice, using SFA API. + Sfi client doesn't work for particular node urns. + """ + self.warning(" Deleting node from slice ") + slicename = self.get("username").replace('_', '.') + slicename = 'ple.' + slicename + self.sfaapi.remove_all_from_slice(slicename) + + def _get_hostname(self): + """ + Get the attribute hostname. + """ + hostname = self.get("hostname") + if hostname: + return hostname + else: + return None + + def _set_hostname_attr(self, node): + """ + Query SFAAPI for the hostname of a certain host hrn and sets the + attribute hostname, it will over write the previous value. + """ + hosts_hrn = self.sfaapi.get_resources_hrn() + for hostname, hrn in hosts_hrn.iteritems(): + if hrn == node: + self.set("hostname", hostname) + + def _check_if_in_slice(self, hosts_hrn): + """ + Check using SFA API if any host hrn from hosts_hrn is in the user's + slice. + """ + slicename = self.get("username").replace('_', '.') + slicename = 'ple.' + slicename + slice_nodes = self.sfaapi.get_slice_resources(slicename)['resource'] + if slice_nodes: + slice_nodes_hrn = self.sfaapi.get_resources_hrn(slice_nodes).values() + else: slice_nodes_hrn = [] + nodes_inslice = list(set(hosts_hrn) & set(slice_nodes_hrn)) + return nodes_inslice + + def _do_ping(self, hostname): + """ + Perform ping command on node's IP matching hostname. + """ + ping_ok = False + ip = self._get_ip(hostname) + if ip: + command = "ping -c4 %s" % ip + (out, err) = lexec(command) + + m = re.search("(\d+)% packet loss", str(out)) + if m and int(m.groups()[0]) < 50: + ping_ok = True + + return ping_ok + + def _blacklist_node(self, host_hrn): + """ + Add mal functioning node to blacklist (in SFA API). + """ + self.warning(" Blacklisting malfunctioning node ") + self.sfaapi.blacklist_resource(host_hrn) + if not self._hostname: + self.set('hostname', None) + + def _reserve(self, host_hrn): + """ + Add node to the list of nodes being provisioned, in order for other RMs + to not try to provision the same one again. + """ + self.sfaapi.reserve_resource(host_hrn) + + def _get_ip(self, hostname): + """ + Query cache for the IP of a node with certain hostname + """ + try: + ip = sshfuncs.gethostbyname(hostname) + except: + # Fail while trying to find the IP + return None + return ip + +
    [docs] def fail_discovery(self): + msg = "Discovery failed. No candidates found for node" + self.error(msg) + raise RuntimeError, msg +
    +
    [docs] def fail_node_not_alive(self, hostname=None): + msg = "Node %s not alive" % hostname + raise RuntimeError, msg +
    +
    [docs] def fail_node_not_available(self, hostname): + msg = "Node %s not available for provisioning" % hostname + raise RuntimeError, msg +
    +
    [docs] def fail_not_enough_nodes(self): + msg = "Not enough nodes available for provisioning" + raise RuntimeError, msg +
    +
    [docs] def fail_sfaapi(self): + msg = "Failing while trying to instanciate the SFA API.\nSet the" + \ + " attributes sfauser and sfaPrivateKey." + raise RuntimeError, msg +
    +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tap.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tap.html new file mode 100644 index 00000000..9b0791ce --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tap.html @@ -0,0 +1,413 @@ + + + + + + + + nepi.resources.planetlab.tap — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.planetlab.tap

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState 
    +from nepi.resources.linux.tap import LinuxTap
    +from nepi.resources.planetlab.node import PlanetlabNode
    +from nepi.util.timefuncs import tnow, tdiffsec
    +
    +import os
    +import time
    +
    +PYTHON_VSYS_VERSION = "1.0"
    +
    +@clsinit_copy
    +
    [docs]class PlanetlabTap(LinuxTap): + _rtype = "planetlab::Tap" + _help = "Creates a TAP device on a PlanetLab host" + _platform = "planetlab" + + @classmethod + def _register_attributes(cls): + snat = Attribute("snat", "Set SNAT=1", + type = Types.Bool, + flags = Flags.Design) + + cls._register_attribute(snat) + + def __init__(self, ec, guid): + super(PlanetlabTap, self).__init__(ec, guid) + self._home = "tap-%s" % self.guid + self._gre_enabled = False + + @property +
    [docs] def node(self): + node = self.get_connected(PlanetlabNode.get_rtype()) + if node: return node[0] + raise RuntimeError, "TAP/TUN devices must be connected to Node" +
    +
    [docs] def upload_sources(self): + scripts = [] + + # vif-creation python script + pl_vif_create = os.path.join(os.path.dirname(__file__), "scripts", + "pl-vif-create.py") + + scripts.append(pl_vif_create) + + # vif-up python script + pl_vif_up = os.path.join(os.path.dirname(__file__), "scripts", + "pl-vif-up.py") + + scripts.append(pl_vif_up) + + # vif-down python script + pl_vif_down = os.path.join(os.path.dirname(__file__), "scripts", + "pl-vif-down.py") + + scripts.append(pl_vif_down) + + # udp-connect python script + udp_connect = os.path.join(os.path.dirname(__file__), + "..", + "linux", + "scripts", + "linux-udp-connect.py") + + scripts.append(udp_connect) + + # tunnel creation python script + tunchannel = os.path.join(os.path.dirname(__file__), + "..", + "linux", + "scripts", + "tunchannel.py") + + scripts.append(tunchannel) + + # Upload scripts + scripts = ";".join(scripts) + + self.node.upload(scripts, + os.path.join(self.node.src_dir), + overwrite = False) + + # upload stop.sh script + stop_command = self.replace_paths(self._stop_command) + + self.node.upload_command(stop_command, + shfile = os.path.join(self.app_home, "stop.sh"), + # Overwrite file every time. + # The stop.sh has the path to the socket, which should change + # on every experiment run. + overwrite = True) +
    +
    [docs] def upload_start_command(self): + super(PlanetlabTap, self).upload_start_command() + + # Planetlab TAPs always add a PI header + self.set("pi", True) + + if not self.gre_enabled: + # After creating the TAP, the pl-vif-create.py script + # will write the name of the TAP to a file. We wait until + # we can read the interface name from the file. + vif_name = self.wait_vif_name() + self.set("deviceName", vif_name) +
    +
    [docs] def wait_vif_name(self, exec_run_home = None): + """ Waits until the vif_name file for the command is generated, + and returns the vif_name for the device """ + vif_name = None + delay = 0.5 + + # The vif_name file will be created in the tap-home, while the + # current execution home might be elsewhere to check for errors + # (e.g. could be a tunnel-home) + if not exec_run_home: + exec_run_home = self.run_home + + for i in xrange(20): + (out, err), proc = self.node.check_output(self.run_home, "vif_name") + + if proc.poll() > 0: + (out, err), proc = self.node.check_errors(exec_run_home) + + if err.strip(): + raise RuntimeError, err + + if out: + vif_name = out.strip() + break + else: + time.sleep(delay) + delay = delay * 1.5 + else: + msg = "Couldn't retrieve vif_name" + self.error(msg, out, err) + raise RuntimeError, msg + + return vif_name +
    +
    [docs] def gre_connect(self, remote_endpoint, connection_app_home, + connection_run_home): + super(PlanetlabTap, self).gre_connect(remote_endpoint, + connection_app_home, connection_run_home) + # After creating the TAP, the pl-vif-create.py script + # will write the name of the TAP to a file. We wait until + # we can read the interface name from the file. + vif_name = self.wait_vif_name(exec_run_home = connection_run_home) + self.set("deviceName", vif_name) + + return True +
    + def _gre_connect_command(self, remote_endpoint, connection_app_home, + connection_run_home): + # Set the remote endpoint, (private) IP of the device + self.set("pointopoint", remote_endpoint.get("ip")) + # Public IP of the node + self.set("greRemote", remote_endpoint.node.get("ip")) + + # Generate GRE connect command + + # Use vif_down command to first kill existing TAP in GRE mode + vif_down_command = self._vif_down_command + + # Use pl-vif-up.py script to configure TAP with peer info + vif_up_command = self._vif_up_command + + command = ["("] + command.append(vif_down_command) + command.append(") ; (") + command.append(vif_up_command) + command.append(")") + + command = " ".join(command) + command = self.replace_paths(command) + + return command + + @property + def _start_command(self): + if self.gre_enabled: + command = [] + else: + command = ["sudo -S python ${SRC}/pl-vif-create.py"] + + command.append("-t %s" % self.vif_type) + command.append("-a %s" % self.get("ip")) + command.append("-n %s" % self.get("prefix")) + command.append("-f %s " % self.vif_name_file) + command.append("-S %s " % self.sock_name) + + if self.get("snat") == True: + command.append("-s") + + if self.get("pointopoint"): + command.append("-p %s" % self.get("pointopoint")) + + if self.get("txqueuelen"): + command.append("-q %s" % self.get("txqueuelen")) + + return " ".join(command) + + @property + def _stop_command(self): + if self.gre_enabled: + command = self._vif_down_command + else: + command = ["sudo -S "] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/pl-vif-down.py") + command.append("-S %s " % self.sock_name) + command = " ".join(command) + + return command + + @property + def _vif_up_command(self): + if self.gre_enabled: + device_name = "%s" % self.guid + else: + device_name = self.get("deviceName") + + # Use pl-vif-up.py script to configure TAP + command = ["sudo -S "] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/pl-vif-up.py") + command.append("-u %s" % self.node.get("username")) + command.append("-N %s" % device_name) + command.append("-t %s" % self.vif_type) + command.append("-a %s" % self.get("ip")) + command.append("-n %s" % self.get("prefix")) + + if self.get("snat") == True: + command.append("-s") + + if self.get("pointopoint"): + command.append("-p %s" % self.get("pointopoint")) + + if self.get("txqueuelen"): + command.append("-q %s" % self.get("txqueuelen")) + + if self.gre_enabled: + command.append("-g %s" % self.get("greKey")) + command.append("-G %s" % self.get("greRemote")) + + command.append("-f %s " % self.vif_name_file) + + return " ".join(command) + + @property + def _vif_down_command(self): + if self.gre_enabled: + device_name = "%s" % self.guid + else: + device_name = self.get("deviceName") + + command = ["sudo -S "] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/pl-vif-down.py") + command.append("-N %s " % device_name) + + if self.gre_enabled: + command.append("-u %s" % self.node.get("username")) + command.append("-t %s" % self.vif_type) + command.append("-D") + + return " ".join(command) + + @property +
    [docs] def vif_name_file(self): + return os.path.join(self.run_home, "vif_name") +
    + @property + def _install(self): + # Install python-vsys and python-passfd + install_vsys = ( " ( " + " python -c 'import vsys, os; vsys.__version__ == \"%(version)s\" or os._exit(1)' " + " ) " + " || " + " ( " + " cd ${SRC} ; " + " hg clone http://nepi.inria.fr/code/python-vsys ; " + " cd python-vsys ; " + " make all ; " + " sudo -S make install " + " )" ) % ({ + "version": PYTHON_VSYS_VERSION + }) + + install_passfd = ( " ( python -c 'import passfd' ) " + " || " + " ( " + " cd ${SRC} ; " + " hg clone http://nepi.inria.fr/code/python-passfd ; " + " cd python-passfd ; " + " make all ; " + " sudo -S make install " + " )" ) + + return "%s ; %s" % ( install_vsys, install_passfd ) + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tun.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tun.html new file mode 100644 index 00000000..c77c0bb3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tun.html @@ -0,0 +1,129 @@ + + + + + + + + nepi.resources.planetlab.tun — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.planetlab.tun

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.resource import clsinit_copy
    +from nepi.resources.planetlab.tap import PlanetlabTap
    +from nepi.resources.linux.tap import LinuxTap
    +
    +import os
    +
    +@clsinit_copy
    +
    [docs]class PlanetlabTun(PlanetlabTap): + _rtype = "planetlab::Tun" + _help = "Creates a TUN device on a PlanetLab host" + _platform = "planetlab" + + def __init__(self, ec, guid): + super(PlanetlabTun, self).__init__(ec, guid) + self._vif_prefix = "tun" + self._vif_type = "IFF_TUN" + self._vif_type_flag = LinuxTap.IFF_TUN + self._home = "%s-%s" % (self.vif_prefix, self.guid) + +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/vroute.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/vroute.html new file mode 100644 index 00000000..e75ef011 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/vroute.html @@ -0,0 +1,276 @@ + + + + + + + + nepi.resources.planetlab.vroute — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.resources.planetlab.vroute

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.execution.attribute import Attribute, Flags, Types
    +from nepi.execution.resource import clsinit_copy, ResourceState 
    +from nepi.resources.linux.application import LinuxApplication
    +from nepi.resources.planetlab.node import PlanetlabNode
    +from nepi.resources.planetlab.tap import PlanetlabTap
    +from nepi.util.timefuncs import tnow, tdiffsec
    +
    +import os
    +import time
    +
    +PYTHON_VSYS_VERSION = "1.0"
    +
    +@clsinit_copy
    +
    [docs]class PlanetlabVroute(LinuxApplication): + _rtype = "planetlab::Vroute" + _help = "Creates a Vroute on a PlanetLab host" + _platform = "planetlab" + + @classmethod + def _register_attributes(cls): + action = Attribute("action", "Either add or del", + allowed = ["add", "del"], + default = "add", + flags = Flags.Design) + + prefix = Attribute("prefix", "IPv4 Prefix", + flags = Flags.Design) + + nexthop = Attribute("nexthop", "IPv4 Address of the next hop", + flags = Flags.Design) + + network = Attribute("network", "IPv4 Network Address", + flags = Flags.Design) + + cls._register_attribute(action) + cls._register_attribute(prefix) + cls._register_attribute(nexthop) + cls._register_attribute(network) + + def __init__(self, ec, guid): + super(PlanetlabVroute, self).__init__(ec, guid) + self._home = "vroute-%s" % self.guid + + @property +
    [docs] def tap(self): + tap = self.get_connected(PlanetlabTap.get_rtype()) + if tap: return tap[0] + return None +
    + @property +
    [docs] def node(self): + node = self.tap.get_connected(PlanetlabNode.get_rtype()) + if node: return node[0] + return None +
    +
    [docs] def upload_sources(self): + # upload vif-creation python script + pl_vroute = os.path.join(os.path.dirname(__file__), + "scripts", + "pl-vroute.py") + + self.node.upload(pl_vroute, + os.path.join(self.node.src_dir, "pl-vroute.py"), + overwrite = False) + + # upload stop.sh script + stop_command = self.replace_paths(self._stop_command) + self.node.upload(stop_command, + os.path.join(self.app_home, "stop.sh"), + text = True, + # Overwrite file every time. + # The stop.sh has the path to the socket, wich should change + # on every experiment run. + overwrite = True) +
    +
    [docs] def upload_start_command(self): + # Overwrite file every time. + # The stop.sh has the path to the socket, wich should change + # on every experiment run. + command = self.get("command") + shfile = os.path.join(self.app_home, "start.sh") + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + overwrite=True) +
    +
    [docs] def do_deploy(self): + if not self.tap or self.tap.state < ResourceState.PROVISIONED: + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("command"): + self.set("command", self._start_command) + + self.do_discover() + self.do_provision() + + self.debug("----- READY ---- ") + self.set_ready() +
    +
    [docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + # Vroute started during deployment + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
    +
    [docs] def do_stop(self): + + command = self.get('command') or '' + + if self.state == ResourceState.STARTED: + self.info("Stopping command '%s'" % self._stop_command) + + command = "bash %s" % os.path.join(self.app_home, "stop.sh") + (out, err), proc = self.execute_command(command, + blocking = True) + + self.set_stopped() +
    +
    [docs] def do_release(self): + # Node needs to wait until all associated RMs are released + # to be released + if not self.get("tearDown"): + self.set("tearDown", self._tear_down_command()) + + super(PlanetlabVroute, self).do_release() +
    + def _tear_down_command(self): + if self.get("action") == "del": + return + + return self._stop_command + + @property + def _start_command(self): + command = ["sudo -S python ${SRC}/pl-vroute.py"] + command.append("-a %s" % self.get("action")) + command.append("-n %s" % self.get("network")) + command.append("-p %s" % self.get("prefix")) + command.append("-g %s" % self.tap.get("pointopoint")) + command.append("-f %s" % self.tap.get("deviceName")) + command = " ".join(command) + + command = self.replace_paths(command) + return command + + @property + def _stop_command(self): + command = ["sudo -S python ${SRC}/pl-vroute.py"] + command.append("-a %s" % "del") + command.append("-n %s" % self.get("network")) + command.append("-p %s" % self.get("prefix")) + command.append("-g %s" % self.get("nexthop")) + command.append("-f %s" % self.tap.get("deviceName")) + command = " ".join(command) + + command = self.replace_paths(command) + return command + +
    [docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/environ.html b/doc/sphinx/_build/html/_modules/nepi/util/environ.html new file mode 100644 index 00000000..1544b5a7 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/environ.html @@ -0,0 +1,293 @@ + + + + + + + + nepi.util.environ — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.environ

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Martin Ferrari <martin.ferrari@inria.fr>
    +
    +
    +
    +import ctypes
    +import imp
    +import sys
    +
    +import os, os.path, re, signal, shutil, socket, subprocess, tempfile
    +
    +__all__ =  ["python", "ssh_path"]
    +__all__ += ["rsh", "tcpdump_path", "sshd_path"]
    +__all__ += ["execute", "backticks"]
    +
    +
    +# Unittest from Python 2.6 doesn't have these decorators
    +def _bannerwrap(f, text):
    +    name = f.__name__
    +    def banner(*args, **kwargs):
    +        sys.stderr.write("*** WARNING: Skipping test %s: `%s'\n" %
    +                (name, text))
    +        return None
    +    return banner
    +
    +def skip(text):
    +    return lambda f: _bannerwrap(f, text)
    +
    +def skipUnless(cond, text):
    +    return (lambda f: _bannerwrap(f, text)) if not cond else lambda f: f
    +
    +def skipIf(cond, text):
    +    return (lambda f: _bannerwrap(f, text)) if cond else lambda f: f
    +
    +def find_bin(name, extra_path = None):
    +    search = []
    +    if "PATH" in os.environ:
    +        search += os.environ["PATH"].split(":")
    +    for pref in ("/", "/usr/", "/usr/local/"):
    +        for d in ("bin", "sbin"):
    +            search.append(pref + d)
    +    if extra_path:
    +        search += extra_path
    +
    +    for d in search:
    +            try:
    +                os.stat(d + "/" + name)
    +                return d + "/" + name
    +            except OSError, e:
    +                if e.errno != os.errno.ENOENT:
    +                    raise
    +    return None
    +
    +def find_bin_or_die(name, extra_path = None):
    +    r = find_bin(name)
    +    if not r:
    +        raise RuntimeError(("Cannot find `%s' command, impossible to " +
    +                "continue.") % name)
    +    return r
    +
    +def find_bin(name, extra_path = None):
    +    search = []
    +    if "PATH" in os.environ:
    +        search += os.environ["PATH"].split(":")
    +    for pref in ("/", "/usr/", "/usr/local/"):
    +        for d in ("bin", "sbin"):
    +            search.append(pref + d)
    +    if extra_path:
    +        search += extra_path
    +
    +    for d in search:
    +            try:
    +                os.stat(d + "/" + name)
    +                return d + "/" + name
    +            except OSError, e:
    +                if e.errno != os.errno.ENOENT:
    +                    raise
    +    return None
    +
    +ssh_path = find_bin_or_die("ssh")
    +python_path = find_bin_or_die("python")
    +
    +# Optional tools
    +rsh_path = find_bin("rsh")
    +tcpdump_path = find_bin("tcpdump")
    +sshd_path = find_bin("sshd")
    +
    +
    [docs]def execute(cmd): + # FIXME: create a global debug variable + #print "[pid %d]" % os.getpid(), " ".join(cmd) + null = open("/dev/null", "r+") + p = subprocess.Popen(cmd, stdout = null, stderr = subprocess.PIPE) + out, err = p.communicate() + if p.returncode != 0: + raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err)) +
    +
    [docs]def backticks(cmd): + p = subprocess.Popen(cmd, stdout = subprocess.PIPE, + stderr = subprocess.PIPE) + out, err = p.communicate() + if p.returncode != 0: + raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err)) + return out + + +# SSH stuff +
    +def gen_ssh_keypair(filename): + ssh_keygen = nepi.util.environ.find_bin_or_die("ssh-keygen") + args = [ssh_keygen, '-q', '-N', '', '-f', filename] + assert subprocess.Popen(args).wait() == 0 + return filename, "%s.pub" % filename + +def add_key_to_agent(filename): + ssh_add = nepi.util.environ.find_bin_or_die("ssh-add") + args = [ssh_add, filename] + null = file("/dev/null", "w") + assert subprocess.Popen(args, stderr = null).wait() == 0 + null.close() + +def get_free_port(): + s = socket.socket() + s.bind(("127.0.0.1", 0)) + port = s.getsockname()[1] + return port + +_SSH_CONF = """ListenAddress 127.0.0.1:%d +Protocol 2 +HostKey %s +UsePrivilegeSeparation no +PubkeyAuthentication yes +PasswordAuthentication no +AuthorizedKeysFile %s +UsePAM no +AllowAgentForwarding yes +PermitRootLogin yes +StrictModes no +PermitUserEnvironment yes +""" + +def gen_sshd_config(filename, port, server_key, auth_keys): + conf = open(filename, "w") + text = _SSH_CONF % (port, server_key, auth_keys) + conf.write(text) + conf.close() + return filename + +def gen_auth_keys(pubkey, output, environ): + #opts = ['from="127.0.0.1/32"'] # fails in stupid yans setup + opts = [] + for k, v in environ.items(): + opts.append('environment="%s=%s"' % (k, v)) + + lines = file(pubkey).readlines() + pubkey = lines[0].split()[0:2] + out = file(output, "w") + out.write("%s %s %s\n" % (",".join(opts), pubkey[0], pubkey[1])) + out.close() + return output + +def start_ssh_agent(): + ssh_agent = nepi.util.environ.find_bin_or_die("ssh-agent") + proc = subprocess.Popen([ssh_agent], stdout = subprocess.PIPE) + (out, foo) = proc.communicate() + assert proc.returncode == 0 + d = {} + for l in out.split("\n"): + match = re.search("^(\w+)=([^ ;]+);.*", l) + if not match: + continue + k, v = match.groups() + os.environ[k] = v + d[k] = v + return d + +def stop_ssh_agent(data): + # No need to gather the pid, ssh-agent knows how to kill itself; after we + # had set up the environment + ssh_agent = nepi.util.environ.find_bin_or_die("ssh-agent") + null = file("/dev/null", "w") + proc = subprocess.Popen([ssh_agent, "-k"], stdout = null) + null.close() + assert proc.wait() == 0 + for k in data: + del os.environ[k] +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/execfuncs.html b/doc/sphinx/_build/html/_modules/nepi/util/execfuncs.html new file mode 100644 index 00000000..7cfccc92 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/execfuncs.html @@ -0,0 +1,356 @@ + + + + + + + + nepi.util.execfuncs — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.execfuncs

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.util.sshfuncs import ProcStatus, STDOUT, log, shell_escape
    +
    +import logging
    +import shlex
    +import subprocess
    +
    +
    [docs]def lexec(command, + user = None, + sudo = False, + env = None): + """ + Executes a local command, returns ((stdout,stderr),process) + """ + if env: + export = '' + for envkey, envval in env.iteritems(): + export += '%s=%s ' % (envkey, envval) + command = "%s %s" % (export, command) + + if sudo: + command = "sudo %s" % command + + # XXX: Doing 'su user' blocks waiting for a password on stdin + #elif user: + # command = "su %s ; %s " % (user, command) + + proc = subprocess.Popen(command, + shell = True, + stdout = subprocess.PIPE, + stderr = subprocess.PIPE) + + out = err = "" + log_msg = "lexec - command %s " % command + + try: + out, err = proc.communicate() + log(log_msg, logging.DEBUG, out, err) + except: + log(log_msg, logging.ERROR, out, err) + raise + + return ((out, err), proc) +
    +
    [docs]def lcopy(source, dest, recursive = False): + """ + Copies from/to localy. + """ + + args = ["cp"] + if recursive: + args.append("-r") + + if isinstance(source, list): + args.extend(source) + else: + args.append(source) + + if isinstance(dest, list): + args.extend(dest) + else: + args.append(dest) + + proc = subprocess.Popen(args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + out = err = "" + command = " ".join(args) + log_msg = " lcopy - command %s " % command + + try: + out, err = proc.communicate() + log(log_msg, logging.DEBUG, out, err) + except: + log(log_msg, logging.ERROR, out, err) + raise + + return ((out, err), proc) +
    +
    [docs]def lspawn(command, pidfile, + stdout = '/dev/null', + stderr = STDOUT, + stdin = '/dev/null', + home = None, + create_home = False, + sudo = False, + user = None): + """ + Spawn a local command such that it will continue working asynchronously. + + Parameters: + command: the command to run - it should be a single line. + + pidfile: path of a (ideally unique to this task) pidfile for tracking the process. + + stdout: path of a file to redirect standard output to - must be a string. + Defaults to /dev/null + stderr: path of a file to redirect standard error to - string or the special STDOUT value + to redirect to the same file stdout was redirected to. Defaults to STDOUT. + stdin: path of a file with input to be piped into the command's standard input + + home: path of a folder to use as working directory - should exist, unless you specify create_home + + create_home: if True, the home folder will be created first with mkdir -p + + sudo: whether the command needs to be executed as root + + Returns: + (stdout, stderr), process + + Of the spawning process, which only captures errors at spawning time. + Usually only useful for diagnostics. + """ + # Start process in a "daemonized" way, using nohup and heavy + # stdin/out redirection to avoid connection issues + if stderr is STDOUT: + stderr = '&1' + else: + stderr = ' ' + stderr + + daemon_command = '{ { %(command)s > %(stdout)s 2>%(stderr)s < %(stdin)s & } ; echo $! 1 > %(pidfile)s ; }' % { + 'command' : command, + 'pidfile' : shell_escape(pidfile), + 'stdout' : stdout, + 'stderr' : stderr, + 'stdin' : stdin, + } + + cmd = "%(create)s%(gohome)s rm -f %(pidfile)s ; %(sudo)s bash -c %(command)s " % { + 'command' : shell_escape(daemon_command), + 'sudo' : 'sudo -S' if sudo else '', + 'pidfile' : shell_escape(pidfile), + 'gohome' : 'cd %s ; ' % (shell_escape(home),) if home else '', + 'create' : 'mkdir -p %s ; ' % (shell_escape(home),) if create_home else '', + } + + (out,err), proc = lexec(cmd) + + if proc.wait(): + raise RuntimeError, "Failed to set up application on host %s: %s %s" % (host, out,err,) + + return ((out,err), proc) +
    +
    [docs]def lgetpid(pidfile): + """ + Check the pidfile of a process spawned with remote_spawn. + + Parameters: + pidfile: the pidfile passed to remote_span + + Returns: + + A (pid, ppid) tuple useful for calling remote_status and remote_kill, + or None if the pidfile isn't valid yet (maybe the process is still starting). + """ + + (out,err), proc = lexec("cat %s" % pidfile ) + + if proc.wait(): + return None + + if out: + try: + return map(int,out.strip().split(' ',1)) + except: + # Ignore, many ways to fail that don't matter that much + return None +
    +
    [docs]def lstatus(pid, ppid): + """ + Check the status of a process spawned with remote_spawn. + + Parameters: + pid/ppid: pid and parent-pid of the spawned process. See remote_check_pid + + Returns: + + One of NOT_STARTED, RUNNING, FINISHED + """ + + (out,err), proc = lexec( + # Check only by pid. pid+ppid does not always work (especially with sudo) + " (( ps --pid %(pid)d -o pid | grep -c %(pid)d && echo 'wait') || echo 'done' ) | tail -n 1" % { + 'ppid' : ppid, + 'pid' : pid, + }) + + if proc.wait(): + return ProcStatus.NOT_STARTED + + status = False + if out: + status = (out.strip() == 'wait') + else: + return ProcStatus.NOT_STARTED + + return ProcStatus.RUNNING if status else ProcStatus.FINISHED +
    +
    [docs]def lkill(pid, ppid, sudo = False): + """ + Kill a process spawned with lspawn. + + First tries a SIGTERM, and if the process does not end in 10 seconds, + it sends a SIGKILL. + + Parameters: + pid/ppid: pid and parent-pid of the spawned process. See remote_check_pid + + sudo: whether the command was run with sudo - careful killing like this. + + Returns: + + Nothing, should have killed the process + """ + + subkill = "$(ps --ppid %(pid)d -o pid h)" % { 'pid' : pid } + cmd = """ +SUBKILL="%(subkill)s" ; +%(sudo)s kill -- -%(pid)d $SUBKILL || /bin/true +%(sudo)s kill %(pid)d $SUBKILL || /bin/true +for x in 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 ; do + sleep 0.2 + if [ `ps --pid %(pid)d -o pid | grep -c %(pid)d` == '0' ]; then + break + else + %(sudo)s kill -- -%(pid)d $SUBKILL || /bin/true + %(sudo)s kill %(pid)d $SUBKILL || /bin/true + fi + sleep 1.8 +done +if [ `ps --pid %(pid)d -o pid | grep -c %(pid)d` != '0' ]; then + %(sudo)s kill -9 -- -%(pid)d $SUBKILL || /bin/true + %(sudo)s kill -9 %(pid)d $SUBKILL || /bin/true +fi +""" + if nowait: + cmd = "( %s ) >/dev/null 2>/dev/null </dev/null &" % (cmd,) + + (out,err),proc = lexec( + cmd % { + 'ppid' : ppid, + 'pid' : pid, + 'sudo' : 'sudo -S' if sudo else '', + 'subkill' : subkill, + }) + +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/guid.html b/doc/sphinx/_build/html/_modules/nepi/util/guid.html new file mode 100644 index 00000000..3c9b96d6 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/guid.html @@ -0,0 +1,123 @@ + + + + + + + + nepi.util.guid — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.guid

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +# FIXME: This class is not thread-safe. 
    +# Should it be made thread-safe?
    +
    [docs]class GuidGenerator(object): + def __init__(self): + self._last_guid = 0 + +
    [docs] def next(self, guid = None): + if guid == None: + guid = self._last_guid + 1 + + self._last_guid = self._last_guid if guid <= self._last_guid else guid + + return guid +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/logger.html b/doc/sphinx/_build/html/_modules/nepi/util/logger.html new file mode 100644 index 00000000..ebcb7ba1 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/logger.html @@ -0,0 +1,145 @@ + + + + + + + + nepi.util.logger — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.logger

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import logging
    +
    +
    [docs]class Logger(object): + def __init__(self, logger_component): + self._logger = logging.getLogger(logger_component) + +
    [docs] def debug(self, msg, out = None, err = None): + self.log(msg, logging.DEBUG, out, err) +
    +
    [docs] def error(self, msg, out = None, err = None): + self.log(msg, logging.ERROR, out, err) +
    +
    [docs] def warning(self, msg, out = None, err = None): + self.log(msg, logging.WARNING, out, err) +
    +
    [docs] def info(self, msg, out = None, err = None): + self.log(msg, logging.INFO, out, err) +
    +
    [docs] def log(self, msg, level, out = None, err = None): + if out: + msg += " - OUT: %s " % out + + if err: + msg += " - ERROR: %s " % err + + msg = self.log_message(msg) + + self.logger.log(level, msg) +
    +
    [docs] def log_message(self, msg): + return msg +
    + @property +
    [docs] def logger(self): + return self._logger
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/manifoldapi.html b/doc/sphinx/_build/html/_modules/nepi/util/manifoldapi.html new file mode 100644 index 00000000..51245ad1 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/manifoldapi.html @@ -0,0 +1,361 @@ + + + + + + + + nepi.util.manifoldapi — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.manifoldapi

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Lucia Guevgeozian Odizzio <lucia.guevgeozian_odizzio@inria.fr>
    +
    +import xmlrpclib
    +import hashlib
    +import threading
    +
    +
    +
    [docs]class MANIFOLDAPI(object): + """ + API to query different data platforms as SFA, TopHat, OML Central Server, + using Manifold Framework, the backend of MySlice. + """ + def __init__(self, username, password, hostname, urlpattern): + + self.auth_pwd = dict(AuthMethod='password', Username=username, + AuthString=password) + self._url = urlpattern % {'hostname':hostname} + self.lock = threading.Lock() + self.auth = self.get_session_key() + + @property +
    [docs] def api(self): + return xmlrpclib.Server(self._url, allow_none = True) +
    +
    [docs] def get_session_key(self): + """ + Retrieves the session key, in order to use the same session for + queries. + """ + query = {'timestamp' : 'now', 'object': 'local:session', + 'filters' : [], 'fields' : [], 'action' : 'create'} + + session = self.api.forward(self.auth_pwd, query) + + if not session['value']: + msg = "Can not authenticate in Manifold API" + raise RuntimeError, msg + + session_key = session['value'][0]['session'] + return dict(AuthMethod='session', session=session_key) +
    +
    [docs] def get_resource_info(self, filters=None, fields=None): + """ + Create and execute the Manifold API Query to get the resources + according fields and filters. + :param filters: resource's constraints for the experiment + :type filters: dict + :param fields: desire fields in the result of the query + :type fields: list + """ + query = {'action' : 'get', 'object' : 'resource'} + + if filters: + filters = self._map_attr_to_resource_filters(filters) + + qfilters = list() + for filtername, filtervalue in filters.iteritems(): + newfilter = [filtername, "==", filtervalue] + qfilters.append(newfilter) + + query['filters'] = qfilters + + if fields: + fields = self._check_valid_fields(fields) + + if fields: + query['fields'] = fields + + return self.api.forward(self.auth, query)['value'] +
    +
    [docs] def get_resource_urn(self, filters=None): + """ + Retrieves the resources urn of the resources matching filters. + """ + return self.get_resource_info(filters, 'urn') +
    +
    [docs] def get_slice_resources(self, slicename): + """ + Retrieves resources attached to user's slice. + return value: list of resources' urn + """ + result = [] + query = {'action' : 'get', 'object' : 'resource', + 'filters' : [['slice','==', slicename]], + 'fields' : ['urn']} + + with self.lock: + value = self.api.forward(self.auth, query)['value'] + + for resource in value: + result.append(resource['urn']) + + return result +
    +
    [docs] def add_resource_to_slice(self, slicename, resource_urn): + """ + Add resource to user's slice. The query needs to specify the new + resource plus the previous resources already in the slice. + """ + resources = self.get_slice_resources(slicename) + resources.append(resource_urn) + + urn_list = list() + for r in resources: + urn_dict = dict() + urn_dict['urn'] = r + urn_list.append(urn_dict) + + query = {'action' : 'update', 'object' : 'slice', + 'filters' : [['slice_hrn','==', slicename]], + 'params' : {'resource' : urn_list}} + + with self.lock: + self.api.forward(self.auth, query) + + resources = self.get_slice_resources(slicename) + if resource_urn in resources: + return True + else: + msg = "Failed while trying to add %s to slice" % resource_urn + print msg + # check how to do warning + return False +
    +
    [docs] def remove_resource_from_slice(self, slicename, resource_urn): + """ + Remove resource from user's slice. The query needs to specify the list + of previous resources in the slice without the one to be remove. + """ + resources = self.get_slice_resources(slicename) + resources.remove(resource_urn) + + urn_list = list() + for r in resources: + urn_dict = dict() + urn_dict['urn'] = r + urn_list.append(urn_dict) + + query = {'action' : 'update', 'object' : 'slice', + 'filters' : [['slice_hrn','==', slicename]], + 'params' : {'resource' : urn_list}} + + with self.lock: + self.api.forward(self.auth, query) + + resources = self.get_slice_resources(slicename) + if resource_urn not in resources: + return True + else: + msg = "Failed while trying to remove %s to slice" % resource_urn + # check how to do warning + return False +
    + def _get_metadata(self): + """ + This method is useful to retrive metadata from different platforms + in order to update fields and possible filters. + """ + query = {'action' : 'get', 'object' : 'local:object', + 'filters' : [['table','=','resource']]} + + res = self.api.forward(self.auth, query) + + valid_fields = list() + for i in res['value'][0]['column']: + valid_fields.append(i['name']) + + return valid_fields + + def _map_attr_to_resource_filters(self, filters): + """ + Depending on the object used for the Manifold query, the filters and + fields can change its sintaxis. A resource field in a slice object + query adds 'resource.' to the field. Other changes don't follow any + particular convention. + """ + #TODO: find out useful filters + attr_to_filter = { + 'hostname' : 'hostname', + 'longitude' : 'longitude', + 'latitude' : 'latitude', + 'network' : 'network', + 'component_id' : 'component_id' + } + + mapped_filters = dict() + for filtername, filtervalue in filters.iteritems(): + if attr_to_filter[filtername]: + new_filtername = attr_to_filter[filtername] + mapped_filters[new_filtername] = filtervalue + + return mapped_filters + + def _check_valid_fields(self, fields): + """ + The fields can be a predefine set, define in the Manifold metadata. + """ + valid_fields = self._get_metadata() + + if not isinstance(fields, list): + fields = [fields] + + for field in fields: + if field not in valid_fields: + fields.remove(field) + #self.warning(" Invalid Manifold field or filter ") + + return fields + +
    +
    [docs]class MANIFOLDAPIFactory(object): + """ + API Factory to manage a map of MANIFOLDAPI instances as key-value pairs, it + instanciate a single instance per key. The key represents the same SFA, + MF (ManiFold) credentials. + """ + + _lock = threading.Lock() + _apis = dict() + + @classmethod +
    [docs] def get_api(cls, username, password, + #hostname = "manifold.pl.sophia.inria.fr", + hostname ="test.myslice.info", + urlpattern = "http://%(hostname)s:7080"): + """ + :param username: Manifold user (also used for MySlice web login) + :type username: str + :param password: Manifold password (also used for MySlice web login) + :type password: str + :param hostname: Hostname of the Manifold API to query SFA, TopHat, etc + :type hostname: str + :param urlpattern: Url of the Manifold API to query SFA, TopHat, etc + :type urlpattern: str + """ + + if username and password: + key = cls.make_key(username, password) + with cls._lock: + api = cls._apis.get(key) + + if not api: + api = MANIFOLDAPI(username, password, hostname, urlpattern) + cls._apis[key] = api + + return api + + return None +
    + @classmethod +
    [docs] def make_key(cls, *args): + skey = "".join(map(str, args)) + return hashlib.md5(skey).hexdigest() +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/netgraph.html b/doc/sphinx/_build/html/_modules/nepi/util/netgraph.html new file mode 100644 index 00000000..c1c5ad87 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/netgraph.html @@ -0,0 +1,434 @@ + + + + + + + + nepi.util.netgraph — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.netgraph

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import ipaddr
    +import networkx
    +import math
    +import random
    +
    +
    [docs]class TopologyType: + LINEAR = "linear" + LADDER = "ladder" + MESH = "mesh" + TREE = "tree" + STAR = "star" + ADHOC = "adhoc" + +## TODO: +## - AQ: Add support for hypergraphs (to be able to add hyper edges to +## model CSMA or wireless networks) +
    +
    [docs]class NetGraph(object): + """ NetGraph represents a network topology. + Network graphs are internally using the networkx library. + + """ + + def __init__(self, **kwargs): + """ A graph can be generated using a specified pattern + (LADDER, MESH, TREE, etc), or provided as an argument. + + :param topology: Undirected graph to use as internal representation + :type topology: networkx.Graph + + :param topo_type: One of TopologyType.{LINEAR,LADDER,MESH,TREE,STAR} + used to automatically generate the topology graph. + :type topo_type: TopologyType + + :param node_count: Number of nodes in the topology to be generated. + :type node_count: int + + :param branches: Number of branches (arms) for the STAR topology. + :type branches: int + + + :param assign_ips: Automatically assign IP addresses to each node. + :type assign_ips: bool + + :param network: Base network segment for IP address assignment. + :type network: str + + :param prefix: Base network prefix for IP address assignment. + :type prefix: int + + :param version: IP version for IP address assignment. + :type version: int + + :param assign_st: Select source and target nodes on the graph. + :type assign_st: bool + + :param sources_targets: dictionary with the list of sources (key = + "sources") and list of targets (key = "targets") if defined, ignore + assign_st + :type sources_targets: dictionary of lists + + :param leaf_source: if True, random sources will be selected only + from leaf nodes. + :type leaf_source: bool + + NOTE: Only point-to-point like network topologies are supported for now. + (Wireless and Ethernet networks were several nodes share the same + edge (hyperedge) can not be modeled for the moment). + + """ + self._topology = kwargs.get("topology") + self._topo_type = kwargs.get("topo_type", TopologyType.ADHOC) + + if not self.topology: + if kwargs.get("node_count"): + node_count = kwargs["node_count"] + branches = kwargs.get("branches") + + self._topology = self.generate_topology(self.topo_type, + node_count, branches = branches) + else: + self._topology = networkx.Graph() + + if kwargs.get("assign_ips"): + network = kwargs.get("network", "10.0.0.0") + prefix = kwargs.get("prefix", 8) + version = kwargs.get("version", 4) + + self.assign_p2p_ips(network = network, prefix = prefix, + version = version) + + sources_targets = kwargs.get("sources_targets") + if sources_targets: + [self.set_source(n) for n in sources_targets["sources"]] + [self.set_target(n) for n in sources_targets["targets"]] + elif kwargs.get("assign_st"): + self.select_target_zero() + self.select_random_source(is_leaf = kwargs.get("leaf_source")) + + @property +
    [docs] def topology(self): + return self._topology +
    + @property +
    [docs] def topo_type(self): + return self._topo_type +
    + @property +
    [docs] def order(self): + return self.topology.order() +
    +
    [docs] def nodes(self): + return self.topology.nodes() +
    +
    [docs] def edges(self): + return self.topology.edges() +
    +
    [docs] def generate_topology(self, topo_type, node_count, branches = None): + if topo_type == TopologyType.LADDER: + total_nodes = node_count/2 + graph = networkx.ladder_graph(total_nodes) + + elif topo_type == TopologyType.LINEAR: + graph = networkx.path_graph(node_count) + + elif topo_type == TopologyType.MESH: + graph = networkx.complete_graph(node_count) + + elif topo_type == TopologyType.TREE: + h = math.log(node_count + 1)/math.log(2) - 1 + graph = networkx.balanced_tree(2, h) + + elif topo_type == TopologyType.STAR: + graph = networkx.Graph() + graph.add_node(0) + + nodesinbranch = (node_count - 1)/ BRANCHES + c = 1 + + for i in xrange(BRANCHES): + prev = 0 + for n in xrange(1, nodesinbranch + 1): + graph.add_node(c) + graph.add_edge(prev, c) + prev = c + c += 1 + + return graph +
    +
    [docs] def add_node(self, nid): + if nid not in self.topology: + self.topology.add_node(nid) +
    +
    [docs] def add_edge(self, nid1, nid2): + self.add_node(nid1) + self.add_node( nid2) + + if nid1 not in self.topology[nid2]: + self.topology.add_edge(nid2, nid1) +
    +
    [docs] def annotate_node_ip(self, nid, ip): + if "ips" not in self.topology.node[nid]: + self.topology.node[nid]["ips"] = list() + + self.topology.node[nid]["ips"].append(ip) +
    +
    [docs] def node_ip_annotations(self, nid): + return self.topology.node[nid].get("ips", []) +
    +
    [docs] def annotate_node(self, nid, name, value): + if not isinstance(value, str) and not isinstance(value, int) and \ + not isinstance(value, float) and not isinstance(value, bool): + raise RuntimeError, "Non-serializable annotation" + + self.topology.node[nid][name] = value +
    +
    [docs] def node_annotation(self, nid, name): + return self.topology.node[nid].get(name) +
    +
    [docs] def node_annotations(self, nid): + return self.topology.node[nid].keys() +
    +
    [docs] def del_node_annotation(self, nid, name): + del self.topology.node[nid][name] +
    +
    [docs] def annotate_edge(self, nid1, nid2, name, value): + if not isinstance(value, str) and not isinstance(value, int) and \ + not isinstance(value, float) and not isinstance(value, bool): + raise RuntimeError, "Non-serializable annotation" + + self.topology.edge[nid1][nid2][name] = value +
    +
    [docs] def annotate_edge_net(self, nid1, nid2, ip1, ip2, mask, network, + prefixlen): + self.topology.edge[nid1][nid2]["net"] = dict() + self.topology.edge[nid1][nid2]["net"][nid1] = ip1 + self.topology.edge[nid1][nid2]["net"][nid2] = ip2 + self.topology.edge[nid1][nid2]["net"]["mask"] = mask + self.topology.edge[nid1][nid2]["net"]["network"] = network + self.topology.edge[nid1][nid2]["net"]["prefix"] = prefixlen +
    +
    [docs] def edge_net_annotation(self, nid1, nid2): + return self.topology.edge[nid1][nid2].get("net", dict()) +
    +
    [docs] def edge_annotation(self, nid1, nid2, name): + return self.topology.edge[nid1][nid2].get(name) +
    +
    [docs] def edge_annotations(self, nid1, nid2): + return self.topology.edge[nid1][nid2].keys() +
    +
    [docs] def del_edge_annotation(self, nid1, nid2, name): + del self.topology.edge[nid1][nid2][name] +
    +
    [docs] def assign_p2p_ips(self, network = "10.0.0.0", prefix = 8, version = 4): + """ Assign IP addresses to each end of each edge of the network graph, + computing all the point to point subnets and addresses in the network + representation. + + :param network: Base network address used for subnetting. + :type network: str + + :param prefix: Prefix for the base network address used for subnetting. + :type prefixt: int + + :param version: IP version (either 4 or 6). + :type version: int + + """ + if networkx.number_connected_components(self.topology) > 1: + raise RuntimeError("Disconnected graph!!") + + # Assign IP addresses to host + netblock = "%s/%d" % (network, prefix) + if version == 4: + net = ipaddr.IPv4Network(netblock) + new_prefix = 30 + elif version == 6: + net = ipaddr.IPv6Network(netblock) + new_prefix = 30 + else: + raise RuntimeError, "Invalid IP version %d" % version + + ## Clear all previusly assigned IPs + for nid in self.topology.nodes(): + self.topology.node[nid]["ips"] = list() + + ## Generate and assign new IPs + sub_itr = net.iter_subnets(new_prefix = new_prefix) + + for nid1, nid2 in self.topology.edges(): + #### Compute subnets for each link + + # get a subnet of base_add with prefix /30 + subnet = sub_itr.next() + mask = subnet.netmask.exploded + network = subnet.network.exploded + prefixlen = subnet.prefixlen + + # get host addresses in that subnet + i = subnet.iterhosts() + addr1 = i.next() + addr2 = i.next() + + ip1 = addr1.exploded + ip2 = addr2.exploded + self.annotate_edge_net(nid1, nid2, ip1, ip2, mask, network, + prefixlen) + + self.annotate_node_ip(nid1, ip1) + self.annotate_node_ip(nid2, ip2) +
    +
    [docs] def get_p2p_info(self, nid1, nid2): + net = self.topology.edge[nid1][nid2]["net"] + return ( net[nid1], net[nid2], net["mask"], net["network"], + net["prefixlen"] ) +
    +
    [docs] def set_source(self, nid): + self.topology.node[nid]["source"] = True +
    +
    [docs] def is_source(self, nid): + return self.topology.node[nid].get("source") +
    +
    [docs] def set_target(self, nid): + self.topology.node[nid]["target"] = True +
    +
    [docs] def is_target(self, nid): + return self.topology.node[nid].get("target") +
    +
    [docs] def targets(self): + """ Returns the nodes that are targets """ + return [nid for nid in self.topology.nodes() \ + if self.topology.node[nid].get("target")] +
    +
    [docs] def sources(self): + """ Returns the nodes that are sources """ + return [nid for nid in self.topology.nodes() \ + if self.topology.node[nid].get("source")] +
    +
    [docs] def select_target_zero(self): + """ Mark the node 0 as target + """ + nid = 0 if 0 in self.topology.nodes() else "0" + self.set_target(nid) +
    +
    [docs] def select_random_source(self, **kwargs): + """ Mark a random node as source. + """ + + # The ladder is a special case because is not symmetric. + if self.topo_type == TopologyType.LADDER: + total_nodes = self.order/2 + leaf1 = total_nodes + leaf2 = total_nodes - 1 + leaves = [leaf1, leaf2] + source = leaves.pop(random.randint(0, len(leaves) - 1)) + else: + # options must not be already sources or targets + options = [ k for k,v in self.topology.degree().iteritems() \ + if (not kwargs.get("is_leaf") or v == 1) \ + and not self.topology.node[k].get("source") \ + and not self.topology.node[k].get("target")] + source = options.pop(random.randint(0, len(options) - 1)) + + self.set_source(source) +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/parallel.html b/doc/sphinx/_build/html/_modules/nepi/util/parallel.html new file mode 100644 index 00000000..24b06927 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/parallel.html @@ -0,0 +1,255 @@ + + + + + + + + nepi.util.parallel — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.parallel

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Claudio Freire <claudio-daniel.freire@inria.fr>
    +#         Alina Quereilhac <alina.quereilhac@inria.fr>
    +#
    +
    +import threading
    +import Queue
    +import traceback
    +import sys
    +import os
    +
    +N_PROCS = None
    +
    +
    [docs]class WorkerThread(threading.Thread): +
    [docs] class QUIT: + pass +
    +
    [docs] def run(self): + while True: + task = self.queue.get() + + if task is self.QUIT: + self.queue.task_done() + break + + try: + try: + callable, args, kwargs = task + rv = callable(*args, **kwargs) + + if self.rvqueue is not None: + self.rvqueue.put(rv) + finally: + self.queue.task_done() + except: + traceback.print_exc(file = sys.stderr) + self.delayed_exceptions.append(sys.exc_info()) +
    +
    [docs] def attach(self, queue, rvqueue, delayed_exceptions): + self.queue = queue + self.rvqueue = rvqueue + self.delayed_exceptions = delayed_exceptions +
    +
    [docs] def quit(self): + self.queue.put(self.QUIT) +
    +
    [docs]class ParallelRun(object): + def __init__(self, maxthreads = None, maxqueue = None, results = True): + self.maxqueue = maxqueue + self.maxthreads = maxthreads + + self.queue = Queue.Queue(self.maxqueue or 0) + + self.delayed_exceptions = [] + + if results: + self.rvqueue = Queue.Queue() + else: + self.rvqueue = None + + self.initialize_workers() + +
    [docs] def initialize_workers(self): + global N_PROCS + + maxthreads = self.maxthreads + + # Compute maximum number of threads allowed by the system + if maxthreads is None: + if N_PROCS is None: + try: + f = open("/proc/cpuinfo") + try: + N_PROCS = sum("processor" in l for l in f) + finally: + f.close() + except: + pass + maxthreads = N_PROCS + + if maxthreads is None: + maxthreads = 4 + + self.workers = [] + + # initialize workers + for x in xrange(maxthreads): + worker = WorkerThread() + worker.attach(self.queue, self.rvqueue, self.delayed_exceptions) + worker.setDaemon(True) + + self.workers.append(worker) +
    + def __del__(self): + self.destroy() + +
    [docs] def empty(self): + while True: + try: + self.queue.get(block = False) + self.queue.task_done() + except Queue.Empty: + break +
    +
    [docs] def destroy(self): + self.join() + + del self.workers[:] +
    +
    [docs] def put(self, callable, *args, **kwargs): + self.queue.put((callable, args, kwargs)) +
    +
    [docs] def put_nowait(self, callable, *args, **kwargs): + self.queue.put_nowait((callable, args, kwargs)) +
    +
    [docs] def start(self): + for worker in self.workers: + if not worker.isAlive(): + worker.start() +
    +
    [docs] def join(self): + # Wait until all queued tasks have been processed + self.queue.join() + + for worker in self.workers: + worker.quit() + + for worker in self.workers: + worker.join() +
    +
    [docs] def sync(self): + if self.delayed_exceptions: + typ,val,loc = self.delayed_exceptions[0] + del self.delayed_exceptions[:] + raise typ,val,loc +
    + def __iter__(self): + if self.rvqueue is not None: + while True: + try: + yield self.rvqueue.get_nowait() + except Queue.Empty: + self.queue.join() + try: + yield self.rvqueue.get_nowait() + except Queue.Empty: + raise StopIteration +
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/parsers/xml_parser.html b/doc/sphinx/_build/html/_modules/nepi/util/parsers/xml_parser.html new file mode 100644 index 00000000..1d92a071 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/parsers/xml_parser.html @@ -0,0 +1,549 @@ + + + + + + + + nepi.util.parsers.xml_parser — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.parsers.xml_parser

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +from nepi.util.netgraph import NetGraph, TopologyType 
    +from nepi.util.timefuncs import stformat, tsformat
    +
    +from xml.dom import minidom
    +
    +import datetime
    +import sys
    +import os
    +
    +STRING = "string"
    +BOOL = "bool"
    +INTEGER = "integer"
    +DOUBLE = "float"
    +
    +
    [docs]def xmlencode(s): + if isinstance(s, str): + rv = s.decode("latin1") + if isinstance(s, datetime.datetime): + rv = tsformat(s) + elif not isinstance(s, unicode): + rv = unicode(s) + else: + rv = s + return rv.replace(u'\x00',u'&#0000;') +
    +
    [docs]def xmldecode(s, cast = str): + ret = s.replace(u'&#0000',u'\x00').encode("ascii") + ret = cast(ret) + if s == "None": + return None + return ret +
    +
    [docs]def from_type(value): + if isinstance(value, bool): + return BOOL + if isinstance(value, int): + return INTEGER + if isinstance(value, float): + return DOUBLE + + return STRING +
    +
    [docs]def to_type(type, value): + if not value: + return value + + if type == STRING: + return str(value) + if type == BOOL: + return value == "True" + if type == INTEGER: + return int(value) + if type == DOUBLE: + return float(value) +
    +
    [docs]class ECXMLParser(object): +
    [docs] def to_xml(self, ec): + + doc = minidom.Document() + + self._ec_to_xml(doc, ec) + + try: + xml = doc.toprettyxml(indent=" ", encoding="UTF-8") + except: + print >>sys.stderr, "Oops: generating XML from %s" % (data,) + raise + + return xml +
    + def _ec_to_xml(self, doc, ec): + ecnode = doc.createElement("experiment") + ecnode.setAttribute("exp_id", xmlencode(ec.exp_id)) + ecnode.setAttribute("run_id", xmlencode(ec.run_id)) + ecnode.setAttribute("nthreads", xmlencode(ec.nthreads)) + ecnode.setAttribute("local_dir", xmlencode(ec.local_dir)) + doc.appendChild(ecnode) + + if ec.netgraph != None: + self._netgraph_to_xml(doc, ecnode, ec) + + rmsnode = doc.createElement("rms") + ecnode.appendChild(rmsnode) + + for guid, rm in ec._resources.iteritems(): + self._rm_to_xml(doc, rmsnode, ec, guid, rm) + + return doc + + def _netgraph_to_xml(self, doc, ecnode, ec): + ngnode = doc.createElement("topology") + ngnode.setAttribute("topo-type", xmlencode(ec.netgraph.topo_type)) + ecnode.appendChild(ngnode) + + self. _netgraph_nodes_to_xml(doc, ngnode, ec) + self. _netgraph_edges_to_xml(doc, ngnode, ec) + + def _netgraph_nodes_to_xml(self, doc, ngnode, ec): + ngnsnode = doc.createElement("nodes") + ngnode.appendChild(ngnsnode) + + for nid in ec.netgraph.nodes(): + ngnnode = doc.createElement("node") + ngnnode.setAttribute("nid", xmlencode(nid)) + ngnnode.setAttribute("nid-type", from_type(nid)) + ngnsnode.appendChild(ngnnode) + + # Mark ources and targets + if ec.netgraph.is_source(nid): + ngnnode.setAttribute("source", xmlencode(True)) + + if ec.netgraph.is_target(nid): + ngnnode.setAttribute("target", xmlencode(True)) + + # Node annotations + annosnode = doc.createElement("node-annotations") + add_annotations = False + for name in ec.netgraph.node_annotations(nid): + add_annotations = True + value = ec.netgraph.node_annotation(nid, name) + annonode = doc.createElement("node-annotation") + annonode.setAttribute("name", xmlencode(name)) + annonode.setAttribute("value", xmlencode(value)) + annonode.setAttribute("type", from_type(value)) + annosnode.appendChild(annonode) + + if add_annotations: + ngnnode.appendChild(annosnode) + + def _netgraph_edges_to_xml(self, doc, ngnode, ec): + ngesnode = doc.createElement("edges") + ngnode.appendChild(ngesnode) + + for nid1, nid2 in ec.netgraph.edges(): + ngenode = doc.createElement("edge") + ngenode.setAttribute("nid1", xmlencode(nid1)) + ngenode.setAttribute("nid1-type", from_type(nid1)) + ngenode.setAttribute("nid2", xmlencode(nid2)) + ngenode.setAttribute("nid2-type", from_type(nid2)) + ngesnode.appendChild(ngenode) + + # Edge annotations + annosnode = doc.createElement("edge-annotations") + add_annotations = False + for name in ec.netgraph.edge_annotations(nid1, nid2): + add_annotations = True + value = ec.netgraph.edge_annotation(nid1, nid2, name) + annonode = doc.createElement("edge-annotation") + annonode.setAttribute("name", xmlencode(name)) + annonode.setAttribute("value", xmlencode(value)) + annonode.setAttribute("type", from_type(value)) + annosnode.appendChild(annonode) + + if add_annotations: + ngenode.appendChild(annosnode) + + def _rm_to_xml(self, doc, rmsnode, ec, guid, rm): + rmnode = doc.createElement("rm") + rmnode.setAttribute("guid", xmlencode(guid)) + rmnode.setAttribute("rtype", xmlencode(rm._rtype)) + rmnode.setAttribute("state", xmlencode(rm._state)) + if rm._start_time: + rmnode.setAttribute("start_time", xmlencode(rm._start_time)) + if rm._stop_time: + rmnode.setAttribute("stop_time", xmlencode(rm._stop_time)) + if rm._discover_time: + rmnode.setAttribute("discover_time", xmlencode(rm._discover_time)) + if rm._provision_time: + rmnode.setAttribute("provision_time", xmlencode(rm._provision_time)) + if rm._ready_time: + rmnode.setAttribute("ready_time", xmlencode(rm._ready_time)) + if rm._release_time: + rmnode.setAttribute("release_time", xmlencode(rm._release_time)) + if rm._failed_time: + rmnode.setAttribute("failed_time", xmlencode(rm._failed_time)) + rmsnode.appendChild(rmnode) + + anode = doc.createElement("attributes") + attributes = False + + for attr in rm._attrs.values(): + if attr.has_changed: + attributes = True + aanode = doc.createElement("attribute") + aanode.setAttribute("name", xmlencode(attr.name)) + aanode.setAttribute("value", xmlencode(attr.value)) + aanode.setAttribute("type", from_type(attr.value)) + anode.appendChild(aanode) + + if attributes: + rmnode.appendChild(anode) + + cnode = doc.createElement("connections") + connections = False + + for guid in rm._connections: + connections = True + ccnode = doc.createElement("connection") + ccnode.setAttribute("guid", xmlencode(guid)) + cnode.appendChild(ccnode) + + if connections: + rmnode.appendChild(cnode) + + cnnode = doc.createElement("conditions") + conditions = False + + for action, conds in rm._conditions.iteritems(): + conditions = True + for (group, state, time) in conds: + ccnnode = doc.createElement("condition") + ccnnode.setAttribute("action", xmlencode(action)) + ccnnode.setAttribute("group", xmlencode(group)) + ccnnode.setAttribute("state", xmlencode(state)) + ccnnode.setAttribute("time", xmlencode(time)) + cnnode.appendChild(ccnnode) + + if conditions: + rmnode.appendChild(cnnode) + + tnode = doc.createElement("traces") + traces = False + + for trace in rm._trcs.values(): + if trace.enabled: + traces = True + ttnode = doc.createElement("trace") + ttnode.setAttribute("name", xmlencode(trace.name)) + tnode.appendChild(ttnode) + + if traces: + rmnode.appendChild(tnode) + +
    [docs] def from_xml(self, xml): + doc = minidom.parseString(xml) + return self._ec_from_xml(doc) +
    + def _ec_from_xml(self, doc): + from nepi.execution.ec import ExperimentController + ec = None + + ecnode_list = doc.getElementsByTagName("experiment") + for ecnode in ecnode_list: + if ecnode.nodeType == doc.ELEMENT_NODE: + exp_id = xmldecode(ecnode.getAttribute("exp_id")) + run_id = xmldecode(ecnode.getAttribute("run_id")) + local_dir = xmldecode(ecnode.getAttribute("local_dir")) + + # Configure number of preocessing threads + nthreads = xmldecode(ecnode.getAttribute("nthreads")) + os.environ["NEPI_NTHREADS"] = nthreads + + # Deserialize netgraph + topology = None + topo_type = None + + netgraph = self._netgraph_from_xml(doc, ecnode) + + if netgraph: + topo_type = netgraph.topo_type + topology = netgraph.topology + + # Instantiate EC + ec = ExperimentController(exp_id = exp_id, local_dir = local_dir, + topology = topology, topo_type = topo_type) + + connections = set() + + rmsnode_list = ecnode.getElementsByTagName("rms") + if rmsnode_list: + rmnode_list = rmsnode_list[0].getElementsByTagName("rm") + for rmnode in rmnode_list: + if rmnode.nodeType == doc.ELEMENT_NODE: + self._rm_from_xml(doc, rmnode, ec, connections) + + for (guid1, guid2) in connections: + ec.register_connection(guid1, guid2) + + break + + return ec + + def _netgraph_from_xml(self, doc, ecnode): + netgraph = None + + topology = ecnode.getElementsByTagName("topology") + if topology: + topology = topology[0] + topo_type = xmldecode(topology.getAttribute("topo-type")) + + netgraph = NetGraph(topo_type = topo_type) + + ngnsnode_list = topology.getElementsByTagName("nodes") + if ngnsnode_list: + ngnsnode = ngnsnode_list[0].getElementsByTagName("node") + for ngnnode in ngnsnode: + nid = xmldecode(ngnnode.getAttribute("nid")) + tipe = xmldecode(ngnnode.getAttribute("nid-type")) + nid = to_type(tipe, nid) + netgraph.add_node(nid) + + if ngnnode.hasAttribute("source"): + netgraph.set_source(nid) + if ngnnode.hasAttribute("target"): + netgraph.set_target(nid) + + annosnode_list = ngnnode.getElementsByTagName("node-annotations") + + if annosnode_list: + annosnode = annosnode_list[0].getElementsByTagName("node-annotation") + for annonode in annosnode: + name = xmldecode(annonode.getAttribute("name")) + + if name == "ips": + ips = xmldecode(annonode.getAttribute("value"), eval) # list + for ip in ips: + netgraph.annotate_node_ip(nid, ip) + else: + value = xmldecode(annonode.getAttribute("value")) + tipe = xmldecode(annonode.getAttribute("type")) + value = to_type(tipe, value) + netgraph.annotate_node(nid, name, value) + + ngesnode_list = topology.getElementsByTagName("edges") + if ngesnode_list: + ngesnode = ngesnode_list[0].getElementsByTagName("edge") + for ngenode in ngesnode: + nid1 = xmldecode(ngenode.getAttribute("nid1")) + tipe1 = xmldecode(ngenode.getAttribute("nid1-type")) + nid1 = to_type(tipe1, nid1) + + nid2 = xmldecode(ngenode.getAttribute("nid2")) + tipe2 = xmldecode(ngenode.getAttribute("nid2-type")) + nid2 = to_type(tipe2, nid2) + + netgraph.add_edge(nid1, nid2) + + annosnode_list = ngenode.getElementsByTagName("edge-annotations") + if annosnode_list: + annosnode = annosnode_list[0].getElementsByTagName("edge-annotation") + for annonode in annosnode: + name = xmldecode(annonode.getAttribute("name")) + + if name == "net": + net = xmldecode(annonode.getAttribute("value"), eval) # dict + netgraph.annotate_edge_net(nid1, nid2, net[nid1], net[nid2], + net["mask"], net["network"], net["prefix"]) + else: + value = xmldecode(annonode.getAttribute("value")) + tipe = xmldecode(annonode.getAttribute("type")) + value = to_type(tipe, value) + netgraph.annotate_edge(nid1, nid2, name, value) + return netgraph + + def _rm_from_xml(self, doc, rmnode, ec, connections): + start_time = None + stop_time = None + discover_time = None + provision_time = None + ready_time = None + release_time = None + failed_time = None + + guid = xmldecode(rmnode.getAttribute("guid"), int) + rtype = xmldecode(rmnode.getAttribute("rtype")) + + # FOR NOW ONLY STATE NEW IS ALLOWED + state = 0 + """ + state = xmldecode(rmnode.getAttribute("state"), int) + + if rmnode.hasAttribute("start_time"): + start_time = xmldecode(rmnode.getAttribute("start_time"), + datetime.datetime) + if rmnode.hasAttribute("stop_time"): + stop_time = xmldecode(rmnode.getAttribute("stop_time"), + datetime.datetime) + if rmnode.hasAttribute("discover_time"): + dicover_time = xmldecode(rmnode.getAttribute("discover_time"), + datetime.datetime) + if rmnode.hasAttribute("provision_time"): + provision_time = xmldecode(rmnode.getAttribute("provision_time"), + datetime.datetime) + if rmnode.hasAttribute("ready_time"): + ready_time = xmldecode(rmnode.getAttribute("ready_time"), + datetime.datetime) + if rmnode.hasAttribute("release_time"): + release_time = xmldecode(rmnode.getAttribute("release_time"), + datetime.datetime) + if rmnode.hasAttribute("failed_time"): + failed_time = xmldecode(rmnode.getAttribute("failed_time"), + datetime.datetime) + """ + + ec.register_resource(rtype, guid = guid) + rm = ec.get_resource(guid) + rm.set_state_time(state, "_start_time", start_time) + rm.set_state_time(state, "_stop_time", stop_time) + rm.set_state_time(state, "_discover_time", discover_time) + rm.set_state_time(state, "_provision_time", provision_time) + rm.set_state_time(state, "_ready_time", ready_time) + rm.set_state_time(state, "_release_time", release_time) + rm.set_state_time(state, "_failed_time", failed_time) + + anode_list = rmnode.getElementsByTagName("attributes") + if anode_list: + aanode_list = anode_list[0].getElementsByTagName("attribute") + for aanode in aanode_list: + name = xmldecode(aanode.getAttribute("name")) + value = xmldecode(aanode.getAttribute("value")) + tipe = xmldecode(aanode.getAttribute("type")) + value = to_type(tipe, value) + rm.set(name, value) + + cnode_list = rmnode.getElementsByTagName("connections") + if cnode_list: + ccnode_list = cnode_list[0].getElementsByTagName("connection") + for ccnode in ccnode_list: + guid2 = xmldecode(ccnode.getAttribute("guid"), int) + connections.add((guid, guid2)) + + tnode_list = rmnode.getElementsByTagName("traces") + if tnode_list: + ttnode_list = tnode_list[0].getElementsByTagName("trace") + for ttnode in ttnode_list: + name = xmldecode(ttnode.getAttribute("name")) + ec.enable_trace(guid, name) + + cnnode_list = rmnode.getElementsByTagName("conditions") + if cnnode_list: + ccnnode_list = cnnode_list[0].getElementsByTagName("condition") + for ccnnode in ccnnode_list: + action = xmldecode(ccnnode.getAttribute("action"), int) + group = xmldecode(ccnnode.getAttribute("group"), eval) # list + state = xmldecode(ccnnode.getAttribute("state"), int) + time = xmldecode(ccnnode.getAttribute("time")) + time = to_type('STRING', time) + ec.register_condition(guid, action, group, state, time = time) +
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/plotter.html b/doc/sphinx/_build/html/_modules/nepi/util/plotter.html new file mode 100644 index 00000000..3276b3c4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/plotter.html @@ -0,0 +1,198 @@ + + + + + + + + nepi.util.plotter — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.plotter

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import logging
    +import os
    +
    +try:
    +    import networkx
    +except ImportError:
    +    msg = "Networkx library is not installed, you will not be able to plot."
    +    logger = logging.Logger("Plotter")
    +    logger.debug(msg)
    +
    +try:
    +    import matplotlib.pyplot as plt
    +except:
    +    msg = ("Matplotlib library is not installed or X11 is not enabled. "
    +        "You will not be able generate PNG plots.")
    +    logger = logging.Logger("Plotter")
    +    logger.debug(msg)
    +
    +
    [docs]class PFormats: + DOT = "dot" + FIGURE = "figure" +
    +
    [docs]class ECPlotter(object): +
    [docs] def plot(self, ec, dirpath = None, format= PFormats.FIGURE, + show = False): + graph, labels = self._ec2graph(ec) + + add_extension = False + + if not dirpath: + import tempfile + dirpath = tempfile.mkdtemp() + + fpath = os.path.join(dirpath, "%s_%s" % (ec.exp_id, ec.run_id)) + + if format == PFormats.FIGURE: + pos = networkx.graphviz_layout(graph, prog="neato") + networkx.draw(graph, pos = pos, node_color="white", + node_size = 500, with_labels=True) + + label = "\n".join(map(lambda v: "%s: %s" % (v[0], v[1]), labels.iteritems())) + plt.annotate(label, xy=(0.05, 0.95), xycoords='axes fraction') + + fpath += ".png" + + plt.savefig(fpath, bbox_inches="tight") + + if show: + plt.show() + + elif format == PFormats.DOT: + fpath += ".dot" + + networkx.write_dot(graph, fpath) + + if show: + import subprocess + subprocess.call(["dot", "-Tps", fpath, "-o", "%s.ps" % fpath]) + subprocess.call(["evince","%s.ps" % fpath]) + + return fpath +
    + def _ec2graph(self, ec): + graph = networkx.Graph(graph = dict(overlap = "false")) + + labels = dict() + connections = set() + + for guid, rm in ec._resources.iteritems(): + label = rm.get_rtype() + + graph.add_node(guid, + label = "%d %s" % (guid, label), + width = 50/72.0, # 1 inch = 72 points + height = 50/72.0, + shape = "circle") + + labels[guid] = label + + for guid2 in rm.connections: + # Avoid adding a same connection twice + if (guid2, guid) not in connections: + connections.add((guid, guid2)) + + for (guid1, guid2) in connections: + graph.add_edge(guid1, guid2) + + return graph, labels
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/rmatcher.html b/doc/sphinx/_build/html/_modules/nepi/util/rmatcher.html new file mode 100644 index 00000000..3279823f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/rmatcher.html @@ -0,0 +1,155 @@ + + + + + + + + nepi.util.rmatcher — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.rmatcher

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +
    [docs]def match_tags(box, all_tags, exact_tags): + """ returns True if box has required tags """ + tall = set(all_tags) + texact = set(exact_tags) + + if texact and box.connections == texact: + return True + + if tall and tall.issubset(box.connections): + return True + + return False +
    +
    [docs]def find_boxes(box, all_tags = None, exact_tags = None, max_depth = 1): + """ Look for the connected boxes with the required tags, doing breath-first + search, until max_depth ( max_depth = None will traverse the entire graph ). + """ + if not all_tags and not exact_tags: + msg = "No matching criteria for resources." + raise RuntimeError(msg) + + queue = set() + # enqueue (depth, box) + queue.add((0, box)) + + traversed = set() + traversed.add(box) + + depth = 0 + + result = set() + + while len(q) > 0: + (depth, a) = queue.pop() + if match_tags(a, all_tags, exact_tags): + result.add(a) + + if not max_depth or depth <= max_depth: + depth += 1 + for b in sorted(a.connections): + if b not in traversed: + traversed.add(b) + queue.add((depth, b)) + + return result
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/serializer.html b/doc/sphinx/_build/html/_modules/nepi/util/serializer.html new file mode 100644 index 00000000..9514b5ea --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/serializer.html @@ -0,0 +1,151 @@ + + + + + + + + nepi.util.serializer — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.serializer

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import datetime
    +import os
    +
    +
    [docs]class SFormats: + XML = "xml" +
    +
    [docs]class ECSerializer(object): +
    [docs] def load(self, filepath, format = SFormats.XML): + if format == SFormats.XML: + from nepi.util.parsers.xml_parser import ECXMLParser + + parser = ECXMLParser() + f = open(filepath, "r") + xml = f.read() + f.close() + + ec = parser.from_xml(xml) + + return ec +
    +
    [docs] def serialize(self, ec, format = SFormats.XML): + if format == SFormats.XML: + from nepi.util.parsers.xml_parser import ECXMLParser + + parser = ECXMLParser() + sec = parser.to_xml(ec) + + return sec +
    +
    [docs] def save(self, ec, dirpath, format = SFormats.XML): + date = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + filename = "%s_%s" % (ec.exp_id, date) + + if format == SFormats.XML: + filepath = os.path.join(dirpath, "%s.xml" % filename) + sec = self.serialize(ec, format = format) + f = open(filepath, "w") + f.write(sec) + f.close() + + return filepath +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/sfaapi.html b/doc/sphinx/_build/html/_modules/nepi/util/sfaapi.html new file mode 100644 index 00000000..1939a77b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/sfaapi.html @@ -0,0 +1,562 @@ + + + + + + + + nepi.util.sfaapi — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.sfaapi

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Lucia Guevgeozian Odizzio <lucia.guevgeozian_odizzio@inria.fr>
    +
    +import threading
    +import hashlib
    +import re
    +import os
    +import time
    +
    +from nepi.util.logger import Logger
    +
    +try:
    +    from sfa.client.sfi import Sfi
    +    from sfa.util.xrn import hrn_to_urn
    +except ImportError:
    +    log = Logger("SFA API")
    +    log.debug("Packages sfa-common or sfa-client not installed.\
    +         Could not import sfa.client.sfi or sfa.util.xrn")
    +
    +from nepi.util.sfarspec_proc import SfaRSpecProcessing
    +
    +
    [docs]class SFAAPI(object): + """ + API for quering the SFA service. It uses Sfi class from the tool sfi client. + """ + def __init__(self, sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, ec, + batch, rtype, timeout): + + self._blacklist = set() + self._reserved = set() + self._resources_cache = None + self._already_cached = False + self._ec = ec + self.apis = 1 + + if batch: + self._testbed_res = rtype + self._count = 0 + self._total = self._get_total_res() + self._slice_resources_batch = list() + + self._log = Logger("SFA API") + self.api = Sfi() + self.rspec_proc = SfaRSpecProcessing() + self.lock_slice = threading.Lock() + self.lock_blist = threading.Lock() + self.lock_resv = threading.Lock() + + self.api.options.timeout = timeout + self.api.options.raw = None + self.api.options.user = sfi_user + self.api.options.auth = sfi_auth + self.api.options.registry = sfi_registry + self.api.options.sm = sfi_sm + self.api.options.user_private_key = private_key + + # Load blacklist from file + if ec.get_global('PlanetlabNode', 'persist_blacklist'): + self._set_blacklist() + + def _set_blacklist(self): + """ + Initialize the blacklist with previous nodes blacklisted, in + previous runs. + """ + nepi_home = os.path.join(os.path.expanduser("~"), ".nepi") + plblacklist_file = os.path.join(nepi_home, "plblacklist.txt") + with open(plblacklist_file, 'r') as f: + hosts_tobl = f.read().splitlines() + if hosts_tobl: + for host in hosts_tobl: + self._blacklist.add(host) + + def _get_total_res(self): + """ + Get the total amount of resources instanciated using this API, + to be able to add them using the same Allocate and Provision + call at once. Specially for Wilabt testbed that doesn't allow + to add slivers after the slice already has some. + """ + rms = list() + res_gids = self._ec.resources + for gid in res_gids: + rm = self._ec.get_resource(gid) + if self._testbed_res.lower() in rm._rtype.lower(): + rms.append(rm) + return rms + + def _sfi_exec_method(self, command, slicename=None, rspec=None, urn=None, action=None): + """ + Execute sfi method, which correspond to SFA call. It can be the following + calls: Describe, Delete, Allocate, Provision, ListResources. + """ + if command in ['describe', 'delete', 'allocate', 'provision', 'action']: + if not slicename: + raise TypeError("The slice hrn is expected for this method %s" % command) + if command == 'allocate' and not rspec: + raise TypeError("RSpec is expected for this method %s" % command) + + if command == 'allocate': + args_list = [slicename, rspec] + else: + args_list = [slicename] + if command != 'delete': + args_list = args_list + ['-o', '/tmp/rspec_output'] + if command == 'action': + args_list = [slicename, action] + + elif command == 'resources': + args_list = ['-o', '/tmp/rspec_output'] + + else: raise TypeError("Sfi method not supported") + + self.api.command = command + self.api.command_parser = self.api.create_parser_command(self.api.command) + (command_options, command_args) = self.api.command_parser.parse_args(args_list) + self.api.command_options = command_options + self.api.read_config() + self.api.bootstrap() + + try: + os.remove("/tmp/rspec_output.rspec") + except OSError: + self._log.debug("Couldn't remove temporary output file for RSpec or it doesn't exist") + + try: + self.api.dispatch(command, command_options, command_args) + with open("/tmp/rspec_output.rspec", "r") as result_file: + result = result_file.read() + return result + except: + self._log.debug(" Couldn't retrive rspec output information from method %s " % command) + return None + +
    [docs] def get_resources_info(self): + """ + Get all resources and its attributes from aggregate. + """ + try: + rspec_slice = self._sfi_exec_method('resources') + except: + raise RuntimeError("Fail to list resources") + + self._resources_cache = self.rspec_proc.parse_sfa_rspec(rspec_slice) + self._already_cached = True + return self._resources_cache +
    +
    [docs] def get_resources_hrn(self, resources=None): + """ + Get list of resources hrn, without the resource info. + """ + if not resources: + if not self._already_cached: + resources = self.get_resources_info()['resource'] + else: + resources = self._resources_cache['resource'] + + component_tohrn = dict() + for resource in resources: + hrn = resource['hrn'].replace('\\', '') + component_tohrn[resource['component_name']] = hrn + + return component_tohrn +
    +
    [docs] def get_slice_resources(self, slicename): + """ + Get resources and info from slice. + """ + try: + with self.lock_slice: + rspec_slice = self._sfi_exec_method('describe', slicename) + except: + self._log.debug("Fail to describe resources for slice %s, slice may be empty" % slicename) + + if rspec_slice is not None: + result = self.rspec_proc.parse_sfa_rspec(rspec_slice) + return result + else: + return {'resource':[],'lease':[]} + +
    +
    [docs] def add_resource_to_slice(self, slicename, resource_hrn, leases=None): + """ + Get the list of resources' urn, build the rspec string and call the allocate + and provision method. + """ + resources_hrn_new = list() + resource_parts = resource_hrn.split('.') + resource_hrn = '.'.join(resource_parts[:2]) + '.' + '\\.'.join(resource_parts[2:]) + resources_hrn_new.append(resource_hrn) + + with self.lock_slice: + rspec_slice = self._sfi_exec_method('describe', slicename) + if rspec_slice is not None: + slice_resources = self.rspec_proc.parse_sfa_rspec(rspec_slice)['resource'] + else: slice_resources = [] + if slice_resources: + slice_resources_hrn = self.get_resources_hrn(slice_resources) + for s_hrn_key, s_hrn_value in slice_resources_hrn.iteritems(): + s_parts = s_hrn_value.split('.') + s_hrn = '.'.join(s_parts[:2]) + '.' + '\\.'.join(s_parts[2:]) + resources_hrn_new.append(s_hrn) + + + resources_urn = self._get_resources_urn(resources_hrn_new) + rspec = self.rspec_proc.build_sfa_rspec(slicename, resources_urn, None, leases) + f = open("/tmp/rspec_input.rspec", "w") + f.truncate(0) + f.write(rspec) + f.close() + + if not os.path.getsize("/tmp/rspec_input.rspec") > 0: + raise RuntimeError("Fail to create rspec file to allocate resource in slice %s" % slicename) + + # ALLOCATE + try: + self._log.debug("Allocating resources in slice %s" % slicename) + out = self._sfi_exec_method('allocate', slicename, "/tmp/rspec_input.rspec") + except: + raise RuntimeError("Fail to allocate resource for slice %s" % slicename) + + if out is not None: + # PROVISION + try: + self._log.debug("Provisioning resources in slice %s" % slicename) + self._sfi_exec_method('provision', slicename) + except: + raise RuntimeError("Fail to provision resource for slice %s" % slicename) + return True +
    +
    [docs] def add_resource_to_slice_batch(self, slicename, resource_hrn, properties=None, leases=None): + """ + Method to add all resources together to the slice. Previous deletion of slivers. + Specially used for wilabt that doesn't allow to add more resources to the slice + after some resources are added. Every sliver have to be deleted and the batch + has to be added at once. + """ + self._count += 1 + self._slice_resources_batch.append(resource_hrn) + resources_hrn_new = list() + if self._count == len(self._total): + check_all_inslice = self._check_all_inslice(self._slice_resources_batch, slicename) + if check_all_inslice == True: + return True + for resource_hrn in self._slice_resources_batch: + resource_parts = resource_hrn.split('.') + resource_hrn = '.'.join(resource_parts[:2]) + '.' + '\\.'.join(resource_parts[2:]) + resources_hrn_new.append(resource_hrn) + with self.lock_slice: + if check_all_inslice != 0: + self._sfi_exec_method('delete', slicename) + time.sleep(480) + + # Re implementing urn from hrn because the library sfa-common doesn't work for wilabt + resources_urn = self._get_urn(resources_hrn_new) + rspec = self.rspec_proc.build_sfa_rspec(slicename, resources_urn, properties, leases) + f = open("/tmp/rspec_input.rspec", "w") + f.truncate(0) + f.write(rspec) + f.close() + + if not os.path.getsize("/tmp/rspec_input.rspec") > 0: + raise RuntimeError("Fail to create rspec file to allocate resources in slice %s" % slicename) + + # ALLOCATE + try: + self._log.debug("Allocating resources in slice %s" % slicename) + out = self._sfi_exec_method('allocate', slicename, "/tmp/rspec_input.rspec") + except: + raise RuntimeError("Fail to allocate resource for slice %s" % slicename) + + if out is not None: + # PROVISION + try: + self._log.debug("Provisioning resources in slice %s" % slicename) + self._sfi_exec_method('provision', slicename) + self._sfi_exec_method('action', slicename=slicename, action='geni_start') + except: + raise RuntimeError("Fail to provision resource for slice %s" % slicename) + return True + else: + raise RuntimeError("Fail to allocate resources for slice %s" % slicename) + + else: + self._log.debug(" Waiting for more nodes to add the batch to the slice ") +
    + def _check_all_inslice(self, resources_hrn, slicename): + slice_res = self.get_slice_resources(slicename)['resource'] + if slice_res: + if len(slice_res[0]['services']) != 0: + slice_res_hrn = self.get_resources_hrn(slice_res).values() + if self._compare_lists(slice_res_hrn, resources_hrn): + return True + else: return len(slice_res_hrn) + return 0 + + def _compare_lists(self, list1, list2): + if len(list1) != len(list2): + return False + for item in list1: + if item not in list2: + return False + return True + + def _get_urn(self, resources_hrn): + """ + Get urn from hrn. + """ + resources_urn = list() + for hrn in resources_hrn: + hrn = hrn.replace("\\", "").split('.') + node = hrn.pop() + auth = '.'.join(hrn) + urn = ['urn:publicid:IDN+', auth, '+node+', node] + urn = ''.join(urn) + resources_urn.append(urn) + return resources_urn + +
    [docs] def remove_resource_from_slice(self, slicename, resource_hrn, leases=None): + """ + Remove slivers from slice. Currently sfi doesn't support removing particular + slivers. + """ + resource_urn = self._get_resources_urn([resource_hrn]).pop() + with self.lock_slice: + try: + self._sfi_exec_method('delete', slicename, urn=resource_urn) + except: + raise RuntimeError("Fail to delete resource for slice %s" % slicename) + return True +
    +
    [docs] def remove_all_from_slice(self, slicename): + """ + De-allocate and de-provision all slivers of the named slice. + Currently sfi doesn't support removing particular + slivers, so this method works only for removing every sliver. Setting the + resource_hrn parameter is not necessary. + """ + with self.lock_slice: + try: + self._sfi_exec_method('delete', slicename) + except: + raise RuntimeError("Fail to delete slivers for slice %s" % slicename) + return True +
    + def _get_resources_urn(self, resources_hrn): + """ + Builds list of resources' urn based on hrn. + """ + resources_urn = list() + + for resource in resources_hrn: + resources_urn.append(hrn_to_urn(resource, 'node')) + + return resources_urn + +
    [docs] def blacklist_resource(self, resource_hrn): + """ + Adding resource_hrn to blacklist, and taking + the resource from the reserved list. + """ + with self.lock_blist: + self._blacklist.add(resource_hrn) + with self.lock_resv: + if resource_hrn in self._reserved: + self._reserved.remove(resource_hrn) +
    +
    [docs] def blacklisted(self, resource_hrn): + """ + Check if the resource is in the blacklist. + """ + with self.lock_blist: + if resource_hrn in self._blacklist: + return True + return False +
    +
    [docs] def reserve_resource(self, resource_hrn): + """ + Add resource to the reserved list. + """ + self._reserved.add(resource_hrn) +
    +
    [docs] def reserved(self, resource_hrn): + """ + Check that the resource in not reserved. + """ + with self.lock_resv: + if resource_hrn in self._reserved: + return True + else: + self.reserve_resource(resource_hrn) + return False +
    +
    [docs] def release(self): + """ + Remove hosts from the reserved and blacklist lists, and in case + the persist attribute is set, it saves the blacklisted hosts + in the blacklist file. + """ + self.apis -= 1 + if self.apis == 0: + blacklist = self._blacklist + self._blacklist = set() + self._reserved = set() +# if self._ecobj.get_global('PlanetlabSfaNode', 'persist_blacklist'): +# if blacklist: +# to_blacklist = list() +# hostnames = self.get_nodes(list(blacklist), ['hostname']) +# for hostname in hostnames: +# to_blacklist.append(hostname['hostname']) +# +# nepi_home = os.path.join(os.path.expanduser("~"), ".nepi") +# plblacklist_file = os.path.join(nepi_home, "plblacklist.txt") +# +# with open(plblacklist_file, 'w') as f: +# for host in to_blacklist: +# f.write("%s\n" % host) +# + +
    +
    [docs]class SFAAPIFactory(object): + """ + API Factory to manage a map of SFAAPI instances as key-value pairs, it + instanciate a single instance per key. The key represents the same SFA, + credentials. + """ + + _lock = threading.Lock() + _apis = dict() + + + @classmethod +
    [docs] def get_api(cls, sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, ec, + batch = False, rtype = None, timeout = None): + + if sfi_user and sfi_sm: + key = cls.make_key(sfi_user, sfi_sm) + with cls._lock: + api = cls._apis.get(key) + + if not api: + api = SFAAPI(sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, + ec, batch, rtype, timeout) + cls._apis[key] = api + else: + api.apis += 1 + + return api + + return None +
    + @classmethod +
    [docs] def make_key(cls, *args): + skey = "".join(map(str, args)) + return hashlib.md5(skey).hexdigest() +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/sfarspec_proc.html b/doc/sphinx/_build/html/_modules/nepi/util/sfarspec_proc.html new file mode 100644 index 00000000..9561359f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/sfarspec_proc.html @@ -0,0 +1,312 @@ + + + + + + + + nepi.util.sfarspec_proc — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.sfarspec_proc

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +from nepi.util.logger import Logger
    +try:
    +    from sfa.rspecs.rspec import RSpec
    +    from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn, urn_to_hrn
    +except ImportError:
    +    log = Logger("SFA RSpec Processing")
    +    log.debug("Package sfa-common not installed.\
    +         Could not import sfa.rspecs.rspec and sfa.util.xrn")
    +
    +from types import StringTypes, ListType
    +
    +
    +
    [docs]class SfaRSpecProcessing(object): + """ + Class to process SFA RSpecs, parse the RSpec replies such as Advertisement RSpecs, + and build in the case of Request RSpecs. + """ + def __init__(self, config=None): + self._log = Logger("SFA RSpec Processing") + self.config = config + +
    [docs] def make_dict_rec(self, obj): + if not obj or isinstance(obj, (StringTypes, bool)): + return obj + if isinstance(obj, list): + objcopy = [] + for x in obj: + objcopy.append(self.make_dict_rec(x)) + return objcopy + # We thus suppose we have a child of dict + objcopy = {} + for k, v in obj.items(): + objcopy[k] = self.make_dict_rec(v) + return objcopy +
    +
    [docs] def parse_sfa_rspec(self, rspec_string): + """ + Parse the RSpec XML as a string. + """ + # rspec_type and rspec_version should be set in the config of the platform, + # we use GENIv3 as default one if not + if self.config: + if 'rspec_type' and 'rspec_version' in self.config: + rspec_version = self.config['rspec_type'] + ' ' + self.config['rspec_version'] + else: + rspec_version = 'GENI 3' + self._log.debug(rspec_version) + rspec = RSpec(rspec_string, version=rspec_version) + + try: + nodes = rspec.version.get_nodes() + except Exception, e: + self._log.warn("Could not retrieve nodes in RSpec: %s" % e) + try: + leases = rspec.version.get_leases() + except Exception, e: + self._log.warn("Could not retrieve leases in RSpec: %s" % e) + try: + links = rspec.version.get_links() + except Exception, e: + self._log.warn("Could not retrieve links in RSpec: %s" % e) + try: + channels = rspec.version.get_channels() + except Exception, e: + self._log.warn("Could not retrieve channels in RSpec: %s" % e) + + resources = [] + # Extend object and Format object field's name + for node in nodes: + node['type'] = 'node' + node['network_hrn'] = Xrn(node['component_id']).authority[0] # network ? XXX + node['hrn'] = urn_to_hrn(node['component_id'])[0] + node['urn'] = node['component_id'] + node['hostname'] = node['component_name'] + node['initscripts'] = node.pop('pl_initscripts') + if 'exclusive' in node and node['exclusive']: + node['exclusive'] = node['exclusive'].lower() == 'true' + + # XXX This should use a MAP as before + if 'position' in node: # iotlab + node['x'] = node['position']['posx'] + node['y'] = node['position']['posy'] + node['z'] = node['position']['posz'] + del node['position'] + + if 'location' in node: + if node['location']: + node['latitude'] = node['location']['latitude'] + node['longitude'] = node['location']['longitude'] + del node['location'] + + # Flatten tags + if 'tags' in node: + if node['tags']: + for tag in node['tags']: + node[tag['tagname']] = tag['value'] + del node['tags'] + + + # We suppose we have children of dict that cannot be serialized + # with xmlrpc, let's make dict + resources.append(self.make_dict_rec(node)) + + # NOTE a channel is a resource and should not be treated independently + # resource + # | + # +----+------+-------+ + # | | | | + # node link channel etc. + #resources.extend(nodes) + #resources.extend(channels) + + return {'resource': resources, 'lease': leases } +# 'channel': channels \ +# } + +
    +
    [docs] def build_sfa_rspec(self, slice_id, resources, properties, leases): + """ + Build the XML RSpec from list of resources' urns. + eg. resources = ["urn:publicid:IDN+ple:modenaple+node+planetlab-1.ing.unimo.it"] + """ + #if isinstance(resources, str): + # resources = eval(resources) + # rspec_type and rspec_version should be set in the config of the platform, + # we use GENIv3 as default one if not + if self.config: + if 'rspec_type' and 'rspec_version' in self.config: + rspec_version = self.config['rspec_type'] + ' ' + self.config['rspec_version'] + else: + rspec_version = 'GENI 3' + + # extend rspec version with "content_type" + rspec_version += ' request' + + rspec = RSpec(version=rspec_version) + + nodes = [] + channels = [] + links = [] + self._log.debug("Building RSpec for resources %s" % resources) + cardinal = 0 + wilab = False + for urn in resources: + # XXX TO BE CORRECTED, this handles None values + if not urn: + continue + self._log.debug(urn) + resource = dict() + # TODO: take into account the case where we send a dict of URNs without keys + #resource['component_id'] = resource.pop('urn') + resource['component_id'] = urn + resource_hrn, resource_type = urn_to_hrn(resource['component_id']) + # build component_manager_id + top_auth = resource_hrn.split('.')[0] + cm = urn.split("+") + resource['component_manager_id'] = "%s+%s+authority+cm" % (cm[0],top_auth) + + if resource_type == 'node': + # XXX dirty hack WiLab !!! +# Commented Lucia, doesn't work for wilabt +# if self.config: +# if 'wilab2' in self.config['sm']: +# resource['client_id'] = "PC" +# resource['sliver_type'] = "raw-pc" + if 'wilab2' in urn: + wilab = True + resource['client_id'] = "node%s" % cardinal + resource['sliver_type'] = "raw-pc" + resource['disk_image'] = "hola" + top_auth = resource_hrn.replace("\\", "").split('.') + top_auth.pop() + top_auth = '.'.join(top_auth) + cm = urn.split("+") + resource['component_manager_id'] = "%s+%s+authority+cm" % (cm[0],top_auth) + cardinal += 1 + nodes.append(resource) + elif resource_type == 'link': + links.append(resource) + elif resource_type == 'channel': + channels.append(resource) + else: + raise Exception, "Not supported type of resource" + + rspec.version.add_nodes(nodes, rspec_content_type="request") + #rspec.version.add_leases(leases) + #rspec.version.add_links(links) + #rspec.version.add_channels(channels) + + #self._log.debug("request rspec: %s"%rspec.toxml()) + string = rspec.toxml() + if wilab and properties is not None: + ## dirty hack for the f4f demo + b = string.split('\n') + for i, n in enumerate(b): + if 'sliver_type name="raw-pc"' in n: + b[i] = '<sliver_type name="raw-pc">' + b.insert(i+1, '<disk_image name="urn:publicid:IDN+wall2.ilabt.iminds.be+image+emulab-ops//%s"/>' % properties['disk_image']) + #b.insert(i+1, '<disk_image name="urn:publicid:IDN+wilab2.ilabt.iminds.be+image+nepi:%s"/>' % properties['disk_image']) + b.insert(i+2, '</sliver_type>') + string = ''.join(b) + self._log.debug("request rspec : %s" % string) + return string +
    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/sshfuncs.html b/doc/sphinx/_build/html/_modules/nepi/util/sshfuncs.html new file mode 100644 index 00000000..b588babb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/sshfuncs.html @@ -0,0 +1,988 @@ + + + + + + + + nepi.util.sshfuncs — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.sshfuncs

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +#         Claudio Freire <claudio-daniel.freire@inria.fr>
    +
    +## TODO: This code needs reviewing !!!
    +
    +import base64
    +import errno
    +import hashlib
    +import logging
    +import os
    +import os.path
    +import re
    +import select
    +import signal
    +import socket
    +import subprocess
    +import threading
    +import time
    +import tempfile
    +
    +_re_inet = re.compile("\d+:\s+(?P<name>[a-z0-9_-]+)\s+inet6?\s+(?P<inet>[a-f0-9.:/]+)\s+(brd\s+[0-9.]+)?.*scope\s+global.*") 
    +
    +logger = logging.getLogger("sshfuncs")
    +
    +
    [docs]def log(msg, level, out = None, err = None): + if out: + msg += " - OUT: %s " % out + + if err: + msg += " - ERROR: %s " % err + + logger.log(level, msg) +
    +if hasattr(os, "devnull"): + DEV_NULL = os.devnull +else: + DEV_NULL = "/dev/null" + +SHELL_SAFE = re.compile('^[-a-zA-Z0-9_=+:.,/]*$') + +
    [docs]class STDOUT: + """ + Special value that when given to rspawn in stderr causes stderr to + redirect to whatever stdout was redirected to. + """ +
    +
    [docs]class ProcStatus: + """ + Codes for status of remote spawned process + """ + # Process is still running + RUNNING = 1 + + # Process is finished + FINISHED = 2 + + # Process hasn't started running yet (this should be very rare) + NOT_STARTED = 3 +
    +hostbyname_cache = dict() +hostbyname_cache_lock = threading.Lock() + +
    [docs]def resolve_hostname(host): + ip = None + + if host in ["localhost", "127.0.0.1", "::1"]: + p = subprocess.Popen("ip -o addr list", shell=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + m = _re_inet.findall(stdout) + ip = m[0][1].split("/")[0] + else: + ip = socket.gethostbyname(host) + + return ip +
    +
    [docs]def gethostbyname(host): + global hostbyname_cache + global hostbyname_cache_lock + + hostbyname = hostbyname_cache.get(host) + if not hostbyname: + with hostbyname_cache_lock: + hostbyname = resolve_hostname(host) + hostbyname_cache[host] = hostbyname + + msg = " Added hostbyname %s - %s " % (host, hostbyname) + log(msg, logging.DEBUG) + + return hostbyname +
    +OPENSSH_HAS_PERSIST = None + +
    [docs]def openssh_has_persist(): + """ The ssh_config options ControlMaster and ControlPersist allow to + reuse a same network connection for multiple ssh sessions. In this + way limitations on number of open ssh connections can be bypassed. + However, older versions of openSSH do not support this feature. + This function is used to determine if ssh connection persist features + can be used. + """ + global OPENSSH_HAS_PERSIST + if OPENSSH_HAS_PERSIST is None: + proc = subprocess.Popen(["ssh","-v"], + stdout = subprocess.PIPE, + stderr = subprocess.STDOUT, + stdin = open("/dev/null","r") ) + out,err = proc.communicate() + proc.wait() + + vre = re.compile(r'OpenSSH_(?:[6-9]|5[.][8-9]|5[.][1-9][0-9]|[1-9][0-9]).*', re.I) + OPENSSH_HAS_PERSIST = bool(vre.match(out)) + return OPENSSH_HAS_PERSIST +
    +
    [docs]def make_server_key_args(server_key, host, port): + """ Returns a reference to a temporary known_hosts file, to which + the server key has been added. + + Make sure to hold onto the temp file reference until the process is + done with it + + :param server_key: the server public key + :type server_key: str + + :param host: the hostname + :type host: str + + :param port: the ssh port + :type port: str + + """ + if port is not None: + host = '%s:%s' % (host, str(port)) + + # Create a temporary server key file + tmp_known_hosts = tempfile.NamedTemporaryFile() + + hostbyname = gethostbyname(host) + + # Add the intended host key + tmp_known_hosts.write('%s,%s %s\n' % (host, hostbyname, server_key)) + + # If we're not in strict mode, add user-configured keys + if os.environ.get('NEPI_STRICT_AUTH_MODE',"").lower() not in ('1','true','on'): + user_hosts_path = '%s/.ssh/known_hosts' % (os.environ.get('HOME',""),) + if os.access(user_hosts_path, os.R_OK): + f = open(user_hosts_path, "r") + tmp_known_hosts.write(f.read()) + f.close() + + tmp_known_hosts.flush() + + return tmp_known_hosts +
    +
    [docs]def make_control_path(agent, forward_x11): + ctrl_path = "/tmp/nepi_ssh" + + if agent: + ctrl_path +="_a" + + if forward_x11: + ctrl_path +="_x" + + ctrl_path += "-%r@%h:%p" + + return ctrl_path +
    +
    [docs]def shell_escape(s): + """ Escapes strings so that they are safe to use as command-line + arguments """ + if SHELL_SAFE.match(s): + # safe string - no escaping needed + return s + else: + # unsafe string - escape + def escp(c): + if (32 <= ord(c) < 127 or c in ('\r','\n','\t')) and c not in ("'",'"'): + return c + else: + return "'$'\\x%02x''" % (ord(c),) + s = ''.join(map(escp,s)) + return "'%s'" % (s,) +
    +
    [docs]def eintr_retry(func): + """Retries a function invocation when a EINTR occurs""" + import functools + @functools.wraps(func) + def rv(*p, **kw): + retry = kw.pop("_retry", False) + for i in xrange(0 if retry else 4): + try: + return func(*p, **kw) + except (select.error, socket.error), args: + if args[0] == errno.EINTR: + continue + else: + raise + except OSError, e: + if e.errno == errno.EINTR: + continue + else: + raise + else: + return func(*p, **kw) + return rv +
    +
    [docs]def rexec(command, host, user, + port = None, + gwuser = None, + gw = None, + agent = True, + sudo = False, + identity = None, + server_key = None, + env = None, + tty = False, + connect_timeout = 30, + retry = 3, + persistent = True, + forward_x11 = False, + blocking = True, + strict_host_checking = True): + """ + Executes a remote command, returns ((stdout,stderr),process) + """ + + tmp_known_hosts = None + if not gw: + hostip = gethostbyname(host) + else: hostip = None + + args = ['ssh', '-C', + # Don't bother with localhost. Makes test easier + '-o', 'NoHostAuthenticationForLocalhost=yes', + '-o', 'ConnectTimeout=%d' % (int(connect_timeout),), + '-o', 'ConnectionAttempts=3', + '-o', 'ServerAliveInterval=30', + '-o', 'TCPKeepAlive=yes', + '-o', 'Batchmode=yes', + '-l', user, hostip or host] + + if persistent and openssh_has_persist(): + args.extend([ + '-o', 'ControlMaster=auto', + '-o', 'ControlPath=%s' % (make_control_path(agent, forward_x11),), + '-o', 'ControlPersist=60' ]) + + if not strict_host_checking: + # Do not check for Host key. Unsafe. + args.extend(['-o', 'StrictHostKeyChecking=no']) + + if gw: + proxycommand = _proxy_command(gw, gwuser, identity) + args.extend(['-o', proxycommand]) + + if agent: + args.append('-A') + + if port: + args.append('-p%d' % port) + + if identity: + identity = os.path.expanduser(identity) + args.extend(('-i', identity)) + + if tty: + args.append('-t') + args.append('-t') + + if forward_x11: + args.append('-X') + + if server_key: + # Create a temporary server key file + tmp_known_hosts = make_server_key_args(server_key, host, port) + args.extend(['-o', 'UserKnownHostsFile=%s' % (tmp_known_hosts.name,)]) + + if sudo: + command = "sudo " + command + + args.append(command) + + log_msg = " rexec - host %s - command %s " % (str(host), " ".join(map(str, args))) + + stdout = stderr = stdin = subprocess.PIPE + if forward_x11: + stdout = stderr = stdin = None + + return _retry_rexec(args, log_msg, + stderr = stderr, + stdin = stdin, + stdout = stdout, + env = env, + retry = retry, + tmp_known_hosts = tmp_known_hosts, + blocking = blocking) +
    +
    [docs]def rcopy(source, dest, + port = None, + gwuser = None, + gw = None, + recursive = False, + identity = None, + server_key = None, + retry = 3, + strict_host_checking = True): + """ + Copies from/to remote sites. + + Source and destination should have the user and host encoded + as per scp specs. + + Source can be a list of files to copy to a single destination, + (in which case it is advised that the destination be a folder), + or a single file in a string. + """ + + # Parse destination as <user>@<server>:<path> + if isinstance(dest, str) and ':' in dest: + remspec, path = dest.split(':',1) + elif isinstance(source, str) and ':' in source: + remspec, path = source.split(':',1) + else: + raise ValueError, "Both endpoints cannot be local" + user,host = remspec.rsplit('@',1) + + # plain scp + tmp_known_hosts = None + + args = ['scp', '-q', '-p', '-C', + # Speed up transfer using blowfish cypher specification which is + # faster than the default one (3des) + '-c', 'blowfish', + # Don't bother with localhost. Makes test easier + '-o', 'NoHostAuthenticationForLocalhost=yes', + '-o', 'ConnectTimeout=60', + '-o', 'ConnectionAttempts=3', + '-o', 'ServerAliveInterval=30', + '-o', 'TCPKeepAlive=yes' ] + + if port: + args.append('-P%d' % port) + + if gw: + proxycommand = _proxy_command(gw, gwuser, identity) + args.extend(['-o', proxycommand]) + + if recursive: + args.append('-r') + + if identity: + identity = os.path.expanduser(identity) + args.extend(('-i', identity)) + + if server_key: + # Create a temporary server key file + tmp_known_hosts = make_server_key_args(server_key, host, port) + args.extend(['-o', 'UserKnownHostsFile=%s' % (tmp_known_hosts.name,)]) + + if not strict_host_checking: + # Do not check for Host key. Unsafe. + args.extend(['-o', 'StrictHostKeyChecking=no']) + + if isinstance(source, list): + args.extend(source) + else: + if openssh_has_persist(): + args.extend([ + '-o', 'ControlMaster=auto', + '-o', 'ControlPath=%s' % (make_control_path(False, False),) + ]) + args.append(source) + + if isinstance(dest, list): + args.extend(dest) + else: + args.append(dest) + + log_msg = " rcopy - host %s - command %s " % (str(host), " ".join(map(str, args))) + + return _retry_rexec(args, log_msg, env = None, retry = retry, + tmp_known_hosts = tmp_known_hosts, + blocking = True) +
    +
    [docs]def rspawn(command, pidfile, + stdout = '/dev/null', + stderr = STDOUT, + stdin = '/dev/null', + home = None, + create_home = False, + sudo = False, + host = None, + port = None, + user = None, + gwuser = None, + gw = None, + agent = None, + identity = None, + server_key = None, + tty = False, + strict_host_checking = True): + """ + Spawn a remote command such that it will continue working asynchronously in + background. + + :param command: The command to run, it should be a single line. + :type command: str + + :param pidfile: Path to a file where to store the pid and ppid of the + spawned process + :type pidfile: str + + :param stdout: Path to file to redirect standard output. + The default value is /dev/null + :type stdout: str + + :param stderr: Path to file to redirect standard error. + If the special STDOUT value is used, stderr will + be redirected to the same file as stdout + :type stderr: str + + :param stdin: Path to a file with input to be piped into the command's standard input + :type stdin: str + + :param home: Path to working directory folder. + It is assumed to exist unless the create_home flag is set. + :type home: str + + :param create_home: Flag to force creation of the home folder before + running the command + :type create_home: bool + + :param sudo: Flag forcing execution with sudo user + :type sudo: bool + + :rtype: tuple + + (stdout, stderr), process + + Of the spawning process, which only captures errors at spawning time. + Usually only useful for diagnostics. + """ + # Start process in a "daemonized" way, using nohup and heavy + # stdin/out redirection to avoid connection issues + if stderr is STDOUT: + stderr = '&1' + else: + stderr = ' ' + stderr + + daemon_command = '{ { %(command)s > %(stdout)s 2>%(stderr)s < %(stdin)s & } ; echo $! 1 > %(pidfile)s ; }' % { + 'command' : command, + 'pidfile' : shell_escape(pidfile), + 'stdout' : stdout, + 'stderr' : stderr, + 'stdin' : stdin, + } + + cmd = "%(create)s%(gohome)s rm -f %(pidfile)s ; %(sudo)s nohup bash -c %(command)s " % { + 'command' : shell_escape(daemon_command), + 'sudo' : 'sudo -S' if sudo else '', + 'pidfile' : shell_escape(pidfile), + 'gohome' : 'cd %s ; ' % (shell_escape(home),) if home else '', + 'create' : 'mkdir -p %s ; ' % (shell_escape(home),) if create_home and home else '', + } + + (out,err),proc = rexec( + cmd, + host = host, + port = port, + user = user, + gwuser = gwuser, + gw = gw, + agent = agent, + identity = identity, + server_key = server_key, + tty = tty, + strict_host_checking = strict_host_checking , + ) + + if proc.wait(): + raise RuntimeError, "Failed to set up application on host %s: %s %s" % (host, out,err,) + + return ((out, err), proc) +
    +@eintr_retry +
    [docs]def rgetpid(pidfile, + host = None, + port = None, + user = None, + gwuser = None, + gw = None, + agent = None, + identity = None, + server_key = None, + strict_host_checking = True): + """ + Returns the pid and ppid of a process from a remote file where the + information was stored. + + :param home: Path to directory where the pidfile is located + :type home: str + + :param pidfile: Name of file containing the pid information + :type pidfile: str + + :rtype: int + + A (pid, ppid) tuple useful for calling rstatus and rkill, + or None if the pidfile isn't valid yet (can happen when process is staring up) + + """ + (out,err),proc = rexec( + "cat %(pidfile)s" % { + 'pidfile' : pidfile, + }, + host = host, + port = port, + user = user, + gwuser = gwuser, + gw = gw, + agent = agent, + identity = identity, + server_key = server_key, + strict_host_checking = strict_host_checking + ) + + if proc.wait(): + return None + + if out: + try: + return map(int,out.strip().split(' ',1)) + except: + # Ignore, many ways to fail that don't matter that much + return None +
    +@eintr_retry +
    [docs]def rstatus(pid, ppid, + host = None, + port = None, + user = None, + gwuser = None, + gw = None, + agent = None, + identity = None, + server_key = None, + strict_host_checking = True): + """ + Returns a code representing the the status of a remote process + + :param pid: Process id of the process + :type pid: int + + :param ppid: Parent process id of process + :type ppid: int + + :rtype: int (One of NOT_STARTED, RUNNING, FINISHED) + + """ + (out,err),proc = rexec( + # Check only by pid. pid+ppid does not always work (especially with sudo) + " (( ps --pid %(pid)d -o pid | grep -c %(pid)d && echo 'wait') || echo 'done' ) | tail -n 1" % { + 'ppid' : ppid, + 'pid' : pid, + }, + host = host, + port = port, + user = user, + gwuser = gwuser, + gw = gw, + agent = agent, + identity = identity, + server_key = server_key, + strict_host_checking = strict_host_checking + ) + + if proc.wait(): + return ProcStatus.NOT_STARTED + + status = False + if err: + if err.strip().find("Error, do this: mount -t proc none /proc") >= 0: + status = True + elif out: + status = (out.strip() == 'wait') + else: + return ProcStatus.NOT_STARTED + return ProcStatus.RUNNING if status else ProcStatus.FINISHED +
    +@eintr_retry +
    [docs]def rkill(pid, ppid, + host = None, + port = None, + user = None, + gwuser = None, + gw = None, + agent = None, + sudo = False, + identity = None, + server_key = None, + nowait = False, + strict_host_checking = True): + """ + Sends a kill signal to a remote process. + + First tries a SIGTERM, and if the process does not end in 10 seconds, + it sends a SIGKILL. + + :param pid: Process id of process to be killed + :type pid: int + + :param ppid: Parent process id of process to be killed + :type ppid: int + + :param sudo: Flag indicating if sudo should be used to kill the process + :type sudo: bool + + """ + subkill = "$(ps --ppid %(pid)d -o pid h)" % { 'pid' : pid } + cmd = """ +SUBKILL="%(subkill)s" ; +%(sudo)s kill -- -%(pid)d $SUBKILL || /bin/true +%(sudo)s kill %(pid)d $SUBKILL || /bin/true +for x in 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 ; do + sleep 0.2 + if [ `ps --pid %(pid)d -o pid | grep -c %(pid)d` == '0' ]; then + break + else + %(sudo)s kill -- -%(pid)d $SUBKILL || /bin/true + %(sudo)s kill %(pid)d $SUBKILL || /bin/true + fi + sleep 1.8 +done +if [ `ps --pid %(pid)d -o pid | grep -c %(pid)d` != '0' ]; then + %(sudo)s kill -9 -- -%(pid)d $SUBKILL || /bin/true + %(sudo)s kill -9 %(pid)d $SUBKILL || /bin/true +fi +""" + if nowait: + cmd = "( %s ) >/dev/null 2>/dev/null </dev/null &" % (cmd,) + + (out,err),proc = rexec( + cmd % { + 'ppid' : ppid, + 'pid' : pid, + 'sudo' : 'sudo -S' if sudo else '', + 'subkill' : subkill, + }, + host = host, + port = port, + user = user, + gwuser = gwuser, + gw = gw, + agent = agent, + identity = identity, + server_key = server_key, + strict_host_checking = strict_host_checking + ) + + # wait, don't leave zombies around + proc.wait() + + return (out, err), proc +
    +def _retry_rexec(args, + log_msg, + stdout = subprocess.PIPE, + stdin = subprocess.PIPE, + stderr = subprocess.PIPE, + env = None, + retry = 3, + tmp_known_hosts = None, + blocking = True): + + for x in xrange(retry): + # connects to the remote host and starts a remote connection + proc = subprocess.Popen(args, + env = env, + stdout = stdout, + stdin = stdin, + stderr = stderr) + + # attach tempfile object to the process, to make sure the file stays + # alive until the process is finished with it + proc._known_hosts = tmp_known_hosts + + # The argument block == False forces to rexec to return immediately, + # without blocking + try: + err = out = " " + if blocking: + #(out, err) = proc.communicate() + # The method communicate was re implemented for performance issues + # when using python subprocess communicate method the ssh commands + # last one minute each + out, err = _communicate(proc, input=None) + + elif stdout: + out = proc.stdout.read() + if proc.poll() and stderr: + err = proc.stderr.read() + + log(log_msg, logging.DEBUG, out, err) + + if proc.poll(): + skip = False + + if err.strip().startswith('ssh: ') or err.strip().startswith('mux_client_hello_exchange: '): + # SSH error, can safely retry + skip = True + elif retry: + # Probably timed out or plain failed but can retry + skip = True + + if skip: + t = x*2 + msg = "SLEEPING %d ... ATEMPT %d - command %s " % ( + t, x, " ".join(args)) + log(msg, logging.DEBUG) + + time.sleep(t) + continue + break + except RuntimeError, e: + msg = " rexec EXCEPTION - TIMEOUT -> %s \n %s" % ( e.args, log_msg ) + log(msg, logging.DEBUG, out, err) + + if retry <= 0: + raise + retry -= 1 + + return ((out, err), proc) + +# POSIX +# Don't remove. The method communicate was re implemented for performance issues +def _communicate(proc, input, timeout=None, err_on_timeout=True): + read_set = [] + write_set = [] + stdout = None # Return + stderr = None # Return + + killed = False + + if timeout is not None: + timelimit = time.time() + timeout + killtime = timelimit + 4 + bailtime = timelimit + 4 + + if proc.stdin: + # Flush stdio buffer. This might block, if the user has + # been writing to .stdin in an uncontrolled fashion. + proc.stdin.flush() + if input: + write_set.append(proc.stdin) + else: + proc.stdin.close() + + if proc.stdout: + read_set.append(proc.stdout) + stdout = [] + + if proc.stderr: + read_set.append(proc.stderr) + stderr = [] + + input_offset = 0 + while read_set or write_set: + if timeout is not None: + curtime = time.time() + if timeout is None or curtime > timelimit: + if curtime > bailtime: + break + elif curtime > killtime: + signum = signal.SIGKILL + else: + signum = signal.SIGTERM + # Lets kill it + os.kill(proc.pid, signum) + select_timeout = 0.5 + else: + select_timeout = timelimit - curtime + 0.1 + else: + select_timeout = 1.0 + + if select_timeout > 1.0: + select_timeout = 1.0 + + try: + rlist, wlist, xlist = select.select(read_set, write_set, [], select_timeout) + except select.error,e: + if e[0] != 4: + raise + else: + continue + + if not rlist and not wlist and not xlist and proc.poll() is not None: + # timeout and process exited, say bye + break + + if proc.stdin in wlist: + # When select has indicated that the file is writable, + # we can write up to PIPE_BUF bytes without risk + # blocking. POSIX defines PIPE_BUF >= 512 + bytes_written = os.write(proc.stdin.fileno(), + buffer(input, input_offset, 512)) + input_offset += bytes_written + + if input_offset >= len(input): + proc.stdin.close() + write_set.remove(proc.stdin) + + if proc.stdout in rlist: + data = os.read(proc.stdout.fileno(), 1024) + if data == "": + proc.stdout.close() + read_set.remove(proc.stdout) + stdout.append(data) + + if proc.stderr in rlist: + data = os.read(proc.stderr.fileno(), 1024) + if data == "": + proc.stderr.close() + read_set.remove(proc.stderr) + stderr.append(data) + + # All data exchanged. Translate lists into strings. + if stdout is not None: + stdout = ''.join(stdout) + if stderr is not None: + stderr = ''.join(stderr) + + # Translate newlines, if requested. We cannot let the file + # object do the translation: It is based on stdio, which is + # impossible to combine with select (unless forcing no + # buffering). + if proc.universal_newlines and hasattr(file, 'newlines'): + if stdout: + stdout = proc._translate_newlines(stdout) + if stderr: + stderr = proc._translate_newlines(stderr) + + if killed and err_on_timeout: + errcode = proc.poll() + raise RuntimeError, ("Operation timed out", errcode, stdout, stderr) + else: + if killed: + proc.poll() + else: + proc.wait() + return (stdout, stderr) + +def _proxy_command(gw, gwuser, gwidentity): + """ + Constructs the SSH ProxyCommand option to add to the SSH command to connect + via a proxy + :param gw: SSH proxy hostname + :type gw: str + + :param gwuser: SSH proxy username + :type gwuser: str + + :param gwidentity: SSH proxy identity file + :type gwidentity: str + + + :rtype: str + + returns the SSH ProxyCommand option. + """ + + proxycommand = 'ProxyCommand=ssh -q ' + if gwidentity: + proxycommand += '-i %s ' % os.path.expanduser(gwidentity) + if gwuser: + proxycommand += '%s' % gwuser + else: + proxycommand += '%r' + proxycommand += '@%s -W %%h:%%p' % gw + + return proxycommand +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/statfuncs.html b/doc/sphinx/_build/html/_modules/nepi/util/statfuncs.html new file mode 100644 index 00000000..73b5db7a --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/statfuncs.html @@ -0,0 +1,136 @@ + + + + + + + + nepi.util.statfuncs — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.statfuncs

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +import math
    +import numpy
    +from scipy import stats
    +
    +
    [docs]def compute_mean(sample): + # TODO: Discard outliers !!!! + + if not sample: + print " CANNOT COMPUTE STATS for ", sample + return (0, 0, 0, 0) + + x = numpy.array(sample) + + # sample mean and standard deviation + n, min_max, mean, var, skew, kurt = stats.describe(x) + std = math.sqrt(var) + + # for the population mean and std ... + # mean = x.mean() + # std = x.std() + + # Calculate confidence interval t-distribution + ## BUG: Use quantil of NORMAL distribution, not t-student quantil distribution + ci = stats.t.interval(0.95, n-1, loc = mean, scale = std/math.sqrt(n)) + + return (mean, std, ci[0], ci[1]) +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/timefuncs.html b/doc/sphinx/_build/html/_modules/nepi/util/timefuncs.html new file mode 100644 index 00000000..398babe9 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/timefuncs.html @@ -0,0 +1,213 @@ + + + + + + + + nepi.util.timefuncs — NEPI 3.0 documentation + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + +

    Source code for nepi.util.timefuncs

    +#
    +#    NEPI, a framework to manage network experiments
    +#    Copyright (C) 2013 INRIA
    +#
    +#    This program is free software: you can redistribute it and/or modify
    +#    it under the terms of the GNU General Public License version 2 as
    +#    published by the Free Software Foundation;
    +#
    +#    This program is distributed in the hope that it will be useful,
    +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +#    GNU General Public License for more details.
    +#
    +#    You should have received a copy of the GNU General Public License
    +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
    +
    +
    +import datetime
    +import re
    +
    +_strf = "%Y%m%d%H%M%S%f"
    +_reabs = re.compile("^\d{20}$")
    +_rerel = re.compile("^(?P<time>\d+(.\d+)?)(?P<units>h|m|s|ms|us)$")
    +
    +# Work around to fix "ImportError: Failed to import _strptime because the import lock is held by another thread."
    +datetime.datetime.strptime("20120807124732894211", _strf)
    +
    +
    [docs]def stformat(sdate): + """ Constructs a datetime object from a string date with + format YYYYMMddHHMMSSffff + + """ + return datetime.datetime.strptime(sdate, _strf).date() +
    +
    [docs]def tsformat(date = None): + """ Formats a datetime object to a string with format YYYYMMddHHMMSSffff. + If no date is given, the current date is used. + + """ + if not date: + date = tnow() + + return date.strftime(_strf) +
    +
    [docs]def tnow(): + """ Returns datetime object with the current time """ + return datetime.datetime.now() +
    +
    [docs]def tdiff(date1, date2): + """ Returns difference ( date1 - date2 ) as a datetime object, + where date1 and date 2 are datetime objects + + """ + return date1 - date2 +
    +def _get_total_seconds(td): + return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 1e6) / 1e6 + +
    [docs]def tdiffsec(date1, date2): + """ Returns the date difference ( date1 - date2 ) in seconds, + where date1 and date 2 are datetime objects + + """ + diff = tdiff(date1, date2) + return _get_total_seconds(diff) +
    +
    [docs]def stabsformat(sdate, dbase = None): + """ Constructs a datetime object from a string date. + The string date can be expressed as an absolute date + ( i.e. format YYYYMMddHHMMSSffff ) or as a relative time + ( e.g. format '5m' or '10s'). + If the date is a relative time and the dbase parameter + is given (dbase must be datetime object), the returned + date will be dbase + sdate. If dbase is None, + current time will be used instead as base time. + + :param date : string date + :type date : date + + """ + + # No date given, return current datetime + if not sdate: + return tnow() + + # Absolute date is given + if _reabs.match(sdate): + return stformat(sdate) + + # Relative time is given + m = _rerel.match(sdate) + if m: + time = float(m.groupdict()['time']) + units = m.groupdict()['units'] + if units == 'h': + delta = datetime.timedelta(hours = time) + elif units == 'm': + delta = datetime.timedelta(minutes = time) + elif units == 's': + delta = datetime.timedelta(seconds = time) + elif units == 'ms': + delta = datetime.timedelta(microseconds = (time*1000)) + else: + delta = datetime.timedelta(microseconds = time) + + if not dbase: + dbase = tnow() + + return dbase + delta + + return None +
    +
    [docs]def compute_delay_ms(timestamp2, timestamp1): + d1 = datetime.datetime.fromtimestamp(float(timestamp1)) + d2 = datetime.datetime.fromtimestamp(float(timestamp2)) + delay = d2 - d1 + + # round up resolution - round up to miliseconds + return delay.total_seconds() * 1000 +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_sources/_layout/modules.txt b/doc/sphinx/_build/html/_sources/_layout/modules.txt new file mode 100644 index 00000000..6486b2cf --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/modules.txt @@ -0,0 +1,7 @@ +nepi +==== + +.. toctree:: + :maxdepth: 4 + + nepi diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ccn.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ccn.txt new file mode 100644 index 00000000..4b3bb6b2 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ccn.txt @@ -0,0 +1,22 @@ +nepi.data.processing.ccn package +================================ + +Submodules +---------- + +nepi.data.processing.ccn.parser module +-------------------------------------- + +.. automodule:: nepi.data.processing.ccn.parser + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.data.processing.ccn + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ping.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ping.txt new file mode 100644 index 00000000..56d3574d --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ping.txt @@ -0,0 +1,22 @@ +nepi.data.processing.ping package +================================= + +Submodules +---------- + +nepi.data.processing.ping.parser module +--------------------------------------- + +.. automodule:: nepi.data.processing.ping.parser + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.data.processing.ping + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.txt new file mode 100644 index 00000000..6f22a0fa --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.txt @@ -0,0 +1,18 @@ +nepi.data.processing package +============================ + +Subpackages +----------- + +.. toctree:: + + nepi.data.processing.ccn + nepi.data.processing.ping + +Module contents +--------------- + +.. automodule:: nepi.data.processing + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.data.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.data.txt new file mode 100644 index 00000000..2841cdc0 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.data.txt @@ -0,0 +1,17 @@ +nepi.data package +================= + +Subpackages +----------- + +.. toctree:: + + nepi.data.processing + +Module contents +--------------- + +.. automodule:: nepi.data + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.execution.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.execution.txt new file mode 100644 index 00000000..c8f46ae0 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.execution.txt @@ -0,0 +1,70 @@ +nepi.execution package +====================== + +Submodules +---------- + +nepi.execution.attribute module +------------------------------- + +.. automodule:: nepi.execution.attribute + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.ec module +------------------------ + +.. automodule:: nepi.execution.ec + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.resource module +------------------------------ + +.. automodule:: nepi.execution.resource + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.runner module +---------------------------- + +.. automodule:: nepi.execution.runner + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.scheduler module +------------------------------- + +.. automodule:: nepi.execution.scheduler + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.tags module +-------------------------- + +.. automodule:: nepi.execution.tags + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.trace module +--------------------------- + +.. automodule:: nepi.execution.trace + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.execution + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.all.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.all.txt new file mode 100644 index 00000000..59459003 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.all.txt @@ -0,0 +1,22 @@ +nepi.resources.all package +========================== + +Submodules +---------- + +nepi.resources.all.collector module +----------------------------------- + +.. automodule:: nepi.resources.all.collector + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.all + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ccn.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ccn.txt new file mode 100644 index 00000000..871cb33f --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ccn.txt @@ -0,0 +1,94 @@ +nepi.resources.linux.ccn package +================================ + +Submodules +---------- + +nepi.resources.linux.ccn.ccnapplication module +---------------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccncat module +-------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccncat + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccncontent module +------------------------------------------ + +.. automodule:: nepi.resources.linux.ccn.ccncontent + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnd module +------------------------------------ + +.. automodule:: nepi.resources.linux.ccn.ccnd + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnpeek module +--------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnpeek + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnping module +--------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnpingserver module +--------------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnpingserver + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnpoke module +--------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnpoke + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnr module +------------------------------------ + +.. automodule:: nepi.resources.linux.ccn.ccnr + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.fibentry module +---------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.fibentry + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.ccn + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.netns.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.netns.txt new file mode 100644 index 00000000..a20d9109 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.netns.txt @@ -0,0 +1,30 @@ +nepi.resources.linux.netns package +================================== + +Submodules +---------- + +nepi.resources.linux.netns.netnsclient module +--------------------------------------------- + +.. automodule:: nepi.resources.linux.netns.netnsclient + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.netns.netnsemulation module +------------------------------------------------ + +.. automodule:: nepi.resources.linux.netns.netnsemulation + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.netns + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.ccn.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.ccn.txt new file mode 100644 index 00000000..a6e08684 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.ccn.txt @@ -0,0 +1,70 @@ +nepi.resources.linux.ns3.ccn package +==================================== + +Submodules +---------- + +nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication module +----------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccndceapplication module +-------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccndceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnddceapplication module +--------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnddceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication module +------------------------------------------------------------ + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication module +------------------------------------------------------------ + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication module +--------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication module +------------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.ns3.ccn + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.txt new file mode 100644 index 00000000..341946ed --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.txt @@ -0,0 +1,69 @@ +nepi.resources.linux.ns3 package +================================ + +Subpackages +----------- + +.. toctree:: + + nepi.resources.linux.ns3.ccn + +Submodules +---------- + +nepi.resources.linux.ns3.fdudptunnel module +------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.fdudptunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3client module +----------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3dceapplication module +------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3dceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3pingdceapplication module +----------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3pingdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3simulation module +--------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3simulation + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.tuntapfdlink module +-------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.tuntapfdlink + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.ns3 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.txt new file mode 100644 index 00000000..40e4309b --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.txt @@ -0,0 +1,167 @@ +nepi.resources.linux package +============================ + +Subpackages +----------- + +.. toctree:: + + nepi.resources.linux.ccn + nepi.resources.linux.netns + nepi.resources.linux.ns3 + +Submodules +---------- + +nepi.resources.linux.application module +--------------------------------------- + +.. automodule:: nepi.resources.linux.application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.channel module +----------------------------------- + +.. automodule:: nepi.resources.linux.channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.debfuncs module +------------------------------------ + +.. automodule:: nepi.resources.linux.debfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.gretunnel module +------------------------------------- + +.. automodule:: nepi.resources.linux.gretunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.interface module +------------------------------------- + +.. automodule:: nepi.resources.linux.interface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.mtr module +------------------------------- + +.. automodule:: nepi.resources.linux.mtr + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.node module +-------------------------------- + +.. automodule:: nepi.resources.linux.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.nping module +--------------------------------- + +.. automodule:: nepi.resources.linux.nping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ping module +-------------------------------- + +.. automodule:: nepi.resources.linux.ping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.route module +--------------------------------- + +.. automodule:: nepi.resources.linux.route + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.rpmfuncs module +------------------------------------ + +.. automodule:: nepi.resources.linux.rpmfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tap module +------------------------------- + +.. automodule:: nepi.resources.linux.tap + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tcpdump module +----------------------------------- + +.. automodule:: nepi.resources.linux.tcpdump + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.traceroute module +-------------------------------------- + +.. automodule:: nepi.resources.linux.traceroute + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tun module +------------------------------- + +.. automodule:: nepi.resources.linux.tun + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tunnel module +---------------------------------- + +.. automodule:: nepi.resources.linux.tunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.udptest module +----------------------------------- + +.. automodule:: nepi.resources.linux.udptest + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.udptunnel module +------------------------------------- + +.. automodule:: nepi.resources.linux.udptunnel + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.netns.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.netns.txt new file mode 100644 index 00000000..eacf7f36 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.netns.txt @@ -0,0 +1,118 @@ +nepi.resources.netns package +============================ + +Submodules +---------- + +nepi.resources.netns.netnsapplication module +-------------------------------------------- + +.. automodule:: nepi.resources.netns.netnsapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsbase module +------------------------------------- + +.. automodule:: nepi.resources.netns.netnsbase + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsclient module +--------------------------------------- + +.. automodule:: nepi.resources.netns.netnsclient + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsemulation module +------------------------------------------ + +.. automodule:: nepi.resources.netns.netnsemulation + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsinterface module +------------------------------------------ + +.. automodule:: nepi.resources.netns.netnsinterface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsipv4address module +-------------------------------------------- + +.. automodule:: nepi.resources.netns.netnsipv4address + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsnode module +------------------------------------- + +.. automodule:: nepi.resources.netns.netnsnode + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsnodeinterface module +---------------------------------------------- + +.. automodule:: nepi.resources.netns.netnsnodeinterface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsroute module +-------------------------------------- + +.. automodule:: nepi.resources.netns.netnsroute + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsserver module +--------------------------------------- + +.. automodule:: nepi.resources.netns.netnsserver + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsswitch module +--------------------------------------- + +.. automodule:: nepi.resources.netns.netnsswitch + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnswrapper module +---------------------------------------- + +.. automodule:: nepi.resources.netns.netnswrapper + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnswrapper_debug module +---------------------------------------------- + +.. automodule:: nepi.resources.netns.netnswrapper_debug + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.netns + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.classes.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.classes.txt new file mode 100644 index 00000000..e489b712 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.classes.txt @@ -0,0 +1,862 @@ +nepi.resources.ns3.classes package +================================== + +Submodules +---------- + +nepi.resources.ns3.classes.aarf_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.aarf_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.aarfcd_wifi_manager module +----------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.aarfcd_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.adhoc_wifi_mac module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.adhoc_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.aloha_noack_net_device module +-------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.aloha_noack_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.amrr_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.amrr_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ap_wifi_mac module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ap_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.arf_wifi_manager module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.arf_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.arp_l3protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.arp_l3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.base_station_net_device module +--------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.base_station_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.binary_error_model module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.binary_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.binary_error_sixlow_model module +----------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.binary_error_sixlow_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.bridge_channel module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.bridge_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.bridge_net_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.bridge_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.bulk_send_application module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.bulk_send_application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.burst_error_model module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.burst_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.cara_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.cara_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_acceleration_mobility_model module +---------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.constant_acceleration_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_position_mobility_model module +------------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_position_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_rate_wifi_manager module +------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_rate_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_speed_propagation_delay_model module +------------------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_speed_propagation_delay_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_velocity_mobility_model module +------------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_velocity_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.cost231propagation_loss_model module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.cost231propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.csma_channel module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.csma_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.csma_net_device module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.csma_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.drop_tail_queue module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.drop_tail_queue + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.dsrdsr_routing module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.dsrdsr_routing + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.emu_net_device module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.emu_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.error_channel module +----------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.error_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.error_channel_sixlow module +------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.error_channel_sixlow + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.error_net_device module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.error_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.fd_net_device module +----------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.fd_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.fixed_rss_loss_model module +------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.fixed_rss_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.friis_propagation_loss_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.friis_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.gauss_markov_mobility_model module +------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.gauss_markov_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.hierarchical_mobility_model module +------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.hierarchical_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model module +------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.icmpv4l4protocol module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.icmpv4l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.icmpv6l4protocol module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.icmpv6l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ideal_wifi_manager module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ideal_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ipv4l3protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.ipv4l3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model module +----------------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.jakes_propagation_loss_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.jakes_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model module +------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.list_error_model module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.list_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.log_distance_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.log_distance_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.loopback_net_device module +----------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.loopback_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lr_wpan_net_device module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lr_wpan_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lte_enb_net_device module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lte_enb_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lte_simple_net_device module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lte_simple_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lte_ue_net_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lte_ue_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.matrix_propagation_loss_model module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.matrix_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.mesh_point_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.mesh_point_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.mesh_wifi_interface_mac module +--------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.mesh_wifi_interface_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.minstrel_wifi_manager module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.minstrel_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.multi_model_spectrum_channel module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.multi_model_spectrum_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.nakagami_propagation_loss_model module +----------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.nakagami_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.nist_error_rate_model module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.nist_error_rate_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.node module +-------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.non_communicating_net_device module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.non_communicating_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ocb_wifi_mac module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ocb_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.oh_buildings_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.oh_buildings_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.okumura_hata_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.okumura_hata_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.on_off_application module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.on_off_application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.onoe_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.onoe_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.packet_sink module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.packet_sink + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ping6 module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ping6 + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.point_to_point_channel module +-------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.point_to_point_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.point_to_point_net_device module +----------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.point_to_point_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.point_to_point_remote_channel module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.point_to_point_remote_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.radvd module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.radvd + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_direction2d_mobility_model module +------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_direction2d_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_propagation_delay_model module +---------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_propagation_delay_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_propagation_loss_model module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_walk2d_mobility_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_walk2d_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_waypoint_mobility_model module +---------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_waypoint_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.range_propagation_loss_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.range_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.rate_error_model module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.rate_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.receive_list_error_model module +---------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.receive_list_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.red_queue module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.red_queue + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.rraa_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.rraa_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.simple_channel module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.simple_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.simple_net_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.simple_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.single_model_spectrum_channel module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.single_model_spectrum_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.six_low_pan_net_device module +-------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.six_low_pan_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.sta_wifi_mac module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.sta_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model module +----------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.subscriber_station_net_device module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.subscriber_station_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.tap_bridge module +-------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.tap_bridge + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.tcp_l4protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.tcp_l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.three_log_distance_propagation_loss_model module +--------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.three_log_distance_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model module +----------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.uan_channel module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.uan_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_client module +-------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_echo_client module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_echo_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_echo_server module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_echo_server + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_l4protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.udp_l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_server module +-------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_server + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_trace_client module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_trace_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.v4ping module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.v4ping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.virtual_net_device module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.virtual_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.waypoint_mobility_model module +--------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.waypoint_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.wifi_net_device module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.wifi_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.yans_error_rate_model module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.yans_error_rate_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.yans_wifi_channel module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.yans_wifi_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.yans_wifi_phy module +----------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.yans_wifi_phy + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.ns3.classes + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.txt new file mode 100644 index 00000000..94356ab8 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.txt @@ -0,0 +1,269 @@ +nepi.resources.ns3 package +========================== + +Subpackages +----------- + +.. toctree:: + + nepi.resources.ns3.classes + +Submodules +---------- + +nepi.resources.ns3.ns3application module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3arpl3protocol module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3arpl3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3base module +--------------------------------- + +.. automodule:: nepi.resources.ns3.ns3base + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3ccndceapplication module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3ccndceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3channel module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3client module +----------------------------------- + +.. automodule:: nepi.resources.ns3.ns3client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3dceapplication module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3dceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3dcehelper module +-------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3dcehelper + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3errormodel module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3errormodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3errorratemodel module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3errorratemodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3fdnetdevice module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3fdnetdevice + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3icmpv4l4protocol module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3icmpv4l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3ipv4l3protocol module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3ipv4l3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3mobilitymodel module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3mobilitymodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3netdevice module +-------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3netdevice + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3node module +--------------------------------- + +.. automodule:: nepi.resources.ns3.ns3node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3pipechanel module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3pipechanel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3propagationdelaymodel module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3propagationdelaymodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3propagationlossmodel module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3propagationlossmodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3queue module +---------------------------------- + +.. automodule:: nepi.resources.ns3.ns3queue + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3route module +---------------------------------- + +.. automodule:: nepi.resources.ns3.ns3route + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3server module +----------------------------------- + +.. automodule:: nepi.resources.ns3.ns3server + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3simulation module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3simulation + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifichannel module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3wifichannel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifimac module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wifimac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifinetdevice module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wifinetdevice + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifiphy module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wifiphy + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifiremotestationmanager module +----------------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3wifiremotestationmanager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wrapper module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wrapper + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wrapper_debug module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wrapper_debug + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.resource_manager_generator module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.resource_manager_generator + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.ns3 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.omf.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.omf.txt new file mode 100644 index 00000000..7dd222ee --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.omf.txt @@ -0,0 +1,118 @@ +nepi.resources.omf package +========================== + +Submodules +---------- + +nepi.resources.omf.application module +------------------------------------- + +.. automodule:: nepi.resources.omf.application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.channel module +--------------------------------- + +.. automodule:: nepi.resources.omf.channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.interface module +----------------------------------- + +.. automodule:: nepi.resources.omf.interface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.messages_5_4 module +-------------------------------------- + +.. automodule:: nepi.resources.omf.messages_5_4 + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.messages_6 module +------------------------------------ + +.. automodule:: nepi.resources.omf.messages_6 + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.node module +------------------------------ + +.. automodule:: nepi.resources.omf.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf5_api module +---------------------------------- + +.. automodule:: nepi.resources.omf.omf5_api + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf6_api module +---------------------------------- + +.. automodule:: nepi.resources.omf.omf6_api + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf6_parser module +------------------------------------- + +.. automodule:: nepi.resources.omf.omf6_parser + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf_api_factory module +----------------------------------------- + +.. automodule:: nepi.resources.omf.omf_api_factory + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf_client module +------------------------------------ + +.. automodule:: nepi.resources.omf.omf_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf_resource module +-------------------------------------- + +.. automodule:: nepi.resources.omf.omf_resource + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.wilabt_node module +------------------------------------- + +.. automodule:: nepi.resources.omf.wilabt_node + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.omf + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.ns3.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.ns3.txt new file mode 100644 index 00000000..a8759d48 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.ns3.txt @@ -0,0 +1,30 @@ +nepi.resources.planetlab.ns3 package +==================================== + +Submodules +---------- + +nepi.resources.planetlab.ns3.fdudptunnel module +----------------------------------------------- + +.. automodule:: nepi.resources.planetlab.ns3.fdudptunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.ns3.tuntapfdlink module +------------------------------------------------ + +.. automodule:: nepi.resources.planetlab.ns3.tuntapfdlink + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.planetlab.ns3 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.openvswitch.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.openvswitch.txt new file mode 100644 index 00000000..edbb21a2 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.openvswitch.txt @@ -0,0 +1,30 @@ +nepi.resources.planetlab.openvswitch package +============================================ + +Submodules +---------- + +nepi.resources.planetlab.openvswitch.ovs module +----------------------------------------------- + +.. automodule:: nepi.resources.planetlab.openvswitch.ovs + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.openvswitch.ovsport module +--------------------------------------------------- + +.. automodule:: nepi.resources.planetlab.openvswitch.ovsport + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.planetlab.openvswitch + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.txt new file mode 100644 index 00000000..9fde12c9 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.txt @@ -0,0 +1,70 @@ +nepi.resources.planetlab package +================================ + +Subpackages +----------- + +.. toctree:: + + nepi.resources.planetlab.ns3 + nepi.resources.planetlab.openvswitch + +Submodules +---------- + +nepi.resources.planetlab.node module +------------------------------------ + +.. automodule:: nepi.resources.planetlab.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.plcapi module +-------------------------------------- + +.. automodule:: nepi.resources.planetlab.plcapi + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.sfa_node module +---------------------------------------- + +.. automodule:: nepi.resources.planetlab.sfa_node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.tap module +----------------------------------- + +.. automodule:: nepi.resources.planetlab.tap + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.tun module +----------------------------------- + +.. automodule:: nepi.resources.planetlab.tun + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.vroute module +-------------------------------------- + +.. automodule:: nepi.resources.planetlab.vroute + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.planetlab + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.txt new file mode 100644 index 00000000..4c1fcfc2 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.txt @@ -0,0 +1,22 @@ +nepi.resources package +====================== + +Subpackages +----------- + +.. toctree:: + + nepi.resources.all + nepi.resources.linux + nepi.resources.netns + nepi.resources.ns3 + nepi.resources.omf + nepi.resources.planetlab + +Module contents +--------------- + +.. automodule:: nepi.resources + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.txt new file mode 100644 index 00000000..aa1d5d30 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.txt @@ -0,0 +1,20 @@ +nepi package +============ + +Subpackages +----------- + +.. toctree:: + + nepi.data + nepi.execution + nepi.resources + nepi.util + +Module contents +--------------- + +.. automodule:: nepi + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.util.parsers.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.util.parsers.txt new file mode 100644 index 00000000..34888c17 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.util.parsers.txt @@ -0,0 +1,22 @@ +nepi.util.parsers package +========================= + +Submodules +---------- + +nepi.util.parsers.xml_parser module +----------------------------------- + +.. automodule:: nepi.util.parsers.xml_parser + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.util.parsers + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.util.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.util.txt new file mode 100644 index 00000000..cf0bc639 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.util.txt @@ -0,0 +1,141 @@ +nepi.util package +================= + +Subpackages +----------- + +.. toctree:: + + nepi.util.parsers + +Submodules +---------- + +nepi.util.environ module +------------------------ + +.. automodule:: nepi.util.environ + :members: + :undoc-members: + :show-inheritance: + +nepi.util.execfuncs module +-------------------------- + +.. automodule:: nepi.util.execfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.util.guid module +--------------------- + +.. automodule:: nepi.util.guid + :members: + :undoc-members: + :show-inheritance: + +nepi.util.logger module +----------------------- + +.. automodule:: nepi.util.logger + :members: + :undoc-members: + :show-inheritance: + +nepi.util.manifoldapi module +---------------------------- + +.. automodule:: nepi.util.manifoldapi + :members: + :undoc-members: + :show-inheritance: + +nepi.util.netgraph module +------------------------- + +.. automodule:: nepi.util.netgraph + :members: + :undoc-members: + :show-inheritance: + +nepi.util.parallel module +------------------------- + +.. automodule:: nepi.util.parallel + :members: + :undoc-members: + :show-inheritance: + +nepi.util.plotter module +------------------------ + +.. automodule:: nepi.util.plotter + :members: + :undoc-members: + :show-inheritance: + +nepi.util.rmatcher module +------------------------- + +.. automodule:: nepi.util.rmatcher + :members: + :undoc-members: + :show-inheritance: + +nepi.util.serializer module +--------------------------- + +.. automodule:: nepi.util.serializer + :members: + :undoc-members: + :show-inheritance: + +nepi.util.sfaapi module +----------------------- + +.. automodule:: nepi.util.sfaapi + :members: + :undoc-members: + :show-inheritance: + +nepi.util.sfarspec_proc module +------------------------------ + +.. automodule:: nepi.util.sfarspec_proc + :members: + :undoc-members: + :show-inheritance: + +nepi.util.sshfuncs module +------------------------- + +.. automodule:: nepi.util.sshfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.util.statfuncs module +-------------------------- + +.. automodule:: nepi.util.statfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.util.timefuncs module +-------------------------- + +.. automodule:: nepi.util.timefuncs + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.util + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/index.txt b/doc/sphinx/_build/html/_sources/index.txt new file mode 100644 index 00000000..6cc4c839 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/index.txt @@ -0,0 +1,91 @@ +.. Nepi documentation master file, created by + sphinx-quickstart on Tue Mar 26 11:36:35 2013. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +NEPI modules +============ + +This page documents the NEPI source code. It presents the NEPI core modules, the Platform resource modules (i.e. drivers to manage platforms), and other miscellaneous classes. + +Core modules +------------ + + * ExperimentController API + + * :mod:`ExperimentController ` + + * ResourceManager API + + * :mod:`ResourceManager ` + + * Attribute module + + * :mod:`Attribute ` + + * Trace module + + * :mod:`Trace ` + + * Runner module + + * :mod:`ExperimentRunner ` + + * Scheduler module + + * :mod:`Scheduler ` + + + +Platform modules +---------------- + + * Live Experiments + + * Linux testbeds + + * :mod:`Linux ` + + * PlanetLab testbeds + + * :mod:`PlanetLab ` + + * OMF testbed + + * :mod:`OMF ` + + * Simulated Experiments + + * ns-3 simulator + + * :mod:`ns-3 ` + + * :mod:`ns-3 in Linux hosts ` + + * Emulated Experiments + + * DCE emulation extension + + * :mod:`DCE Application ` + + * :mod:`DCE Linux Application ` + + * NetNS emulator + + * :mod:`NetNS ` + +Miscellaneous modules +--------------------- + + * :mod:`Util ` + +.. toctree:: + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/doc/sphinx/_build/html/_static/ajax-loader.gif b/doc/sphinx/_build/html/_static/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..61faf8cab23993bd3e1560bff0668bd628642330 GIT binary patch literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nno%(3)e{?)x>&1u}A`t?OF7Z|1gRivOgXi&7IyQd1Pl zGfOfQ60;I3a`F>X^fL3(@);C=vM_KlFfb_o=k{|A33hf2a5d61U}gjg=>Rd%XaNQW zW@Cw{|b%Y*pl8F?4B9 zlo4Fz*0kZGJabY|>}Okf0}CCg{u4`zEPY^pV?j2@h+|igy0+Kz6p;@SpM4s6)XEMg z#3Y4GX>Hjlml5ftdH$4x0JGdn8~MX(U~_^d!Hi)=HU{V%g+mi8#UGbE-*ao8f#h+S z2a0-5+vc7MU$e-NhmBjLIC1v|)9+Im8x1yacJ7{^tLX(ZhYi^rpmXm0`@ku9b53aN zEXH@Y3JaztblgpxbJt{AtE1ad1Ca>{v$rwwvK(>{m~Gf_=-Ro7Fk{#;i~+{{>QtvI yb2P8Zac~?~=sRA>$6{!(^3;ZP0TPFR(G_-UDU(8Jl0?(IXu$~#4A!880|o%~Al1tN literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/html/_static/basic.css b/doc/sphinx/_build/html/_static/basic.css new file mode 100644 index 00000000..967e36ce --- /dev/null +++ b/doc/sphinx/_build/html/_static/basic.css @@ -0,0 +1,537 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 170px; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + width: 30px; +} + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- general body styles --------------------------------------------------- */ + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.optional { + font-size: 1.3em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +tt.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +tt.descclassname { + background-color: transparent; +} + +tt.xref, a tt { + background-color: transparent; + font-weight: bold; +} + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/doc/sphinx/_build/html/_static/comment-bright.png b/doc/sphinx/_build/html/_static/comment-bright.png new file mode 100644 index 0000000000000000000000000000000000000000..551517b8c83b76f734ff791f847829a760ad1903 GIT binary patch literal 3500 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 A2LJ#7 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/html/_static/comment.png b/doc/sphinx/_build/html/_static/comment.png new file mode 100644 index 0000000000000000000000000000000000000000..92feb52b8824c6b0f59b658b1196c61de9162a95 GIT binary patch literal 3445 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 Xn!ZpXD%P(H00000NkvXXu0mjf;VkfoEM{Qf z76xHPhFNnYfP(BLp1!W^HyC+E#mt?nx10eANtU=qlsM<-=BDPAFgO>bCYGe8D3oWG zWGJ|M`UZqI@`(c#nR~i8hHzY8+H1+jpulh_>fir3VfEN66+L= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this); + }); + } + } + return this.each(function() { + highlight(this); + }); +}; + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated == 'undefined') + return string; + return (typeof translated == 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated == 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) == 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this == '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/doc/sphinx/_build/html/_static/down-pressed.png b/doc/sphinx/_build/html/_static/down-pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..6f7ad782782e4f8e39b0c6e15c7344700cdd2527 GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*yM+OLB!qm#z$3ZNi+iKnkC`z>}Z23@f-Ava~9&<9T!#}JFtXD=!G zGdl{fK6ro2OGiOl+hKvH6i=D3%%Y^j`yIkRn!8O>@bG)IQR0{Kf+mxNd=_WScA8u_ z3;8(7x2){m9`nt+U(Nab&1G)!{`SPVpDX$w8McLTzAJ39wprG3p4XLq$06M`%}2Yk zRPPsbES*dnYm1wkGL;iioAUB*Or2kz6(-M_r_#Me-`{mj$Z%( literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/html/_static/down.png b/doc/sphinx/_build/html/_static/down.png new file mode 100644 index 0000000000000000000000000000000000000000..3003a88770de3977d47a2ba69893436a2860f9e7 GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*yM+OLB!qm#z$3ZNi+iKnkC`z>}xaV3tUZ$qnrLa#kt978NlpS`ru z&)HFc^}^>{UOEce+71h5nn>6&w6A!ieNbu1wh)UGh{8~et^#oZ1# z>T7oM=FZ~xXWnTo{qnXm$ZLOlqGswI_m2{XwVK)IJmBjW{J3-B3x@C=M{ShWt#fYS9M?R;8K$~YwlIqwf>VA7q=YKcwf2DS4Zj5inDKXXB1zl=(YO3ST6~rDq)&z z*o>z)=hxrfG-cDBW0G$!?6{M<$@{_4{m1o%Ub!naEtn|@^frU1tDnm{r-UW|!^@B8 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/html/_static/file.png b/doc/sphinx/_build/html/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..d18082e397e7e54f20721af768c4c2983258f1b4 GIT binary patch literal 392 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP$HyOL$D9)yc9|lc|nKf<9@eUiWd>3GuTC!a5vdfWYEazjncPj5ZQX%+1 zt8B*4=d)!cdDz4wr^#OMYfqGz$1LDFF>|#>*O?AGil(WEs?wLLy{Gj2J_@opDm%`dlax3yA*@*N$G&*ukFv>P8+2CBWO(qz zD0k1@kN>hhb1_6`&wrCswzINE(evt-5C1B^STi2@PmdKI;Vst0PQB6!2kdN literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/html/_static/jquery.js b/doc/sphinx/_build/html/_static/jquery.js new file mode 100644 index 00000000..12581195 --- /dev/null +++ b/doc/sphinx/_build/html/_static/jquery.js @@ -0,0 +1,9404 @@ +/*! + * jQuery JavaScript Library v1.7.2 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu Aug 1 23:20:30 BRT 2013 + */ +(function( window, undefined ) { + +// Use the correct document accordingly with window argument (sandbox) +var document = window.document, + navigator = window.navigator, + location = window.location; +var jQuery = (function() { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = ( context ? context.ownerDocument || context : document ); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.7.2", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.add( fn ); + + return this; + }, + + eq: function( i ) { + i = +i; + return i === -1 ? + this.slice( i ) : + this.slice( i, i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.fireWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).off( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery.Callbacks( "once memory" ); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array, i ) { + var len; + + if ( array ) { + if ( indexOf ) { + return indexOf.call( array, elem, i ); + } + + len = array.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in array && array[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, pass ) { + var exec, + bulk = key == null, + i = 0, + length = elems.length; + + // Sets many values + if ( key && typeof key === "object" ) { + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); + } + chainable = 1; + + // Sets one value + } else if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = pass === undefined && jQuery.isFunction( value ); + + if ( bulk ) { + // Bulk operations only iterate when executing function values + if ( exec ) { + exec = fn; + fn = function( elem, key, value ) { + return exec.call( jQuery( elem ), value ); + }; + + // Otherwise they run against the entire set + } else { + fn.call( elems, value ); + fn = null; + } + } + + if ( fn ) { + for (; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + } + + chainable = 1; + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +return jQuery; + +})(); + + +// String to Object flags format cache +var flagsCache = {}; + +// Convert String-formatted flags into Object-formatted ones and store in cache +function createFlags( flags ) { + var object = flagsCache[ flags ] = {}, + i, length; + flags = flags.split( /\s+/ ); + for ( i = 0, length = flags.length; i < length; i++ ) { + object[ flags[i] ] = true; + } + return object; +} + +/* + * Create a callback list using the following parameters: + * + * flags: an optional list of space-separated flags that will change how + * the callback list behaves + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible flags: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( flags ) { + + // Convert flags from String-formatted to Object-formatted + // (we check in cache first) + flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; + + var // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = [], + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Add one or several callbacks to the list + add = function( args ) { + var i, + length, + elem, + type, + actual; + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + // Inspect recursively + add( elem ); + } else if ( type === "function" ) { + // Add if not in unique mode and callback is not in + if ( !flags.unique || !self.has( elem ) ) { + list.push( elem ); + } + } + } + }, + // Fire callbacks + fire = function( context, args ) { + args = args || []; + memory = !flags.memory || [ context, args ]; + fired = true; + firing = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { + memory = true; // Mark as halted + break; + } + } + firing = false; + if ( list ) { + if ( !flags.once ) { + if ( stack && stack.length ) { + memory = stack.shift(); + self.fireWith( memory[ 0 ], memory[ 1 ] ); + } + } else if ( memory === true ) { + self.disable(); + } else { + list = []; + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + var length = list.length; + add( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away, unless previous + // firing was halted (stopOnFalse) + } else if ( memory && memory !== true ) { + firingStart = length; + fire( memory[ 0 ], memory[ 1 ] ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + var args = arguments, + argIndex = 0, + argLength = args.length; + for ( ; argIndex < argLength ; argIndex++ ) { + for ( var i = 0; i < list.length; i++ ) { + if ( args[ argIndex ] === list[ i ] ) { + // Handle firingIndex and firingLength + if ( firing ) { + if ( i <= firingLength ) { + firingLength--; + if ( i <= firingIndex ) { + firingIndex--; + } + } + } + // Remove the element + list.splice( i--, 1 ); + // If we have some unicity property then + // we only need to do this once + if ( flags.unique ) { + break; + } + } + } + } + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + if ( list ) { + var i = 0, + length = list.length; + for ( ; i < length; i++ ) { + if ( fn === list[ i ] ) { + return true; + } + } + } + return false; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory || memory === true ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( stack ) { + if ( firing ) { + if ( !flags.once ) { + stack.push( [ context, args ] ); + } + } else if ( !( flags.once && memory ) ) { + fire( context, args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + + + +var // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + + Deferred: function( func ) { + var doneList = jQuery.Callbacks( "once memory" ), + failList = jQuery.Callbacks( "once memory" ), + progressList = jQuery.Callbacks( "memory" ), + state = "pending", + lists = { + resolve: doneList, + reject: failList, + notify: progressList + }, + promise = { + done: doneList.add, + fail: failList.add, + progress: progressList.add, + + state: function() { + return state; + }, + + // Deprecated + isResolved: doneList.fired, + isRejected: failList.fired, + + then: function( doneCallbacks, failCallbacks, progressCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); + return this; + }, + always: function() { + deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); + return this; + }, + pipe: function( fnDone, fnFail, fnProgress ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ], + progress: [ fnProgress, "notify" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + obj = promise; + } else { + for ( var key in promise ) { + obj[ key ] = promise[ key ]; + } + } + return obj; + } + }, + deferred = promise.promise({}), + key; + + for ( key in lists ) { + deferred[ key ] = lists[ key ].fire; + deferred[ key + "With" ] = lists[ key ].fireWith; + } + + // Handle state + deferred.done( function() { + state = "resolved"; + }, failList.disable, progressList.lock ).fail( function() { + state = "rejected"; + }, doneList.disable, progressList.lock ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = sliceDeferred.call( arguments, 0 ), + i = 0, + length = args.length, + pValues = new Array( length ), + count = length, + pCount = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(), + promise = deferred.promise(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( deferred, args ); + } + }; + } + function progressFunc( i ) { + return function( value ) { + pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + deferred.notifyWith( promise, pValues ); + }; + } + if ( length > 1 ) { + for ( ; i < length; i++ ) { + if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return promise; + } +}); + + + + +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + fragment, + tds, + events, + eventName, + i, + isSupported, + div = document.createElement( "div" ), + documentElement = document.documentElement; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
    a"; + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute("href") === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form(#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + pixelMargin: true + }; + + // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead + jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat"); + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for ( i in { + submit: 1, + change: 1, + focusin: 1 + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + fragment.removeChild( div ); + + // Null elements to avoid leaks in IE + fragment = select = opt = div = input = null; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, outer, inner, table, td, offsetSupport, + marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight, + paddingMarginBorderVisibility, paddingMarginBorder, + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + conMarginTop = 1; + paddingMarginBorder = "padding:0;margin:0;border:"; + positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;"; + paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;"; + style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;"; + html = "
    " + + "" + + "
    "; + + container = document.createElement("div"); + container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; + body.insertBefore( container, body.firstChild ); + + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + div.innerHTML = "
    t
    "; + tds = div.getElementsByTagName( "td" ); + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( window.getComputedStyle ) { + div.innerHTML = ""; + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.style.width = "2px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.innerHTML = ""; + div.style.width = div.style.padding = "1px"; + div.style.border = 0; + div.style.overflow = "hidden"; + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = "block"; + div.style.overflow = "visible"; + div.innerHTML = "
    "; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + } + + div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility; + div.innerHTML = html; + + outer = div.firstChild; + inner = outer.firstChild; + td = outer.nextSibling.firstChild.firstChild; + + offsetSupport = { + doesNotAddBorder: ( inner.offsetTop !== 5 ), + doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) + }; + + inner.style.position = "fixed"; + inner.style.top = "20px"; + + // safari subtracts parent border width here which is 5px + offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); + inner.style.position = inner.style.top = ""; + + outer.style.overflow = "hidden"; + outer.style.position = "relative"; + + offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); + offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); + + if ( window.getComputedStyle ) { + div.style.marginTop = "1%"; + support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%"; + } + + if ( typeof container.style.zoom !== "undefined" ) { + container.style.zoom = 1; + } + + body.removeChild( container ); + marginDiv = div = container = null; + + jQuery.extend( support, offsetSupport ); + }); + + return support; +})(); + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var privateCache, thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, + isEvents = name === "events"; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = ++jQuery.uuid; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + privateCache = thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Users should not attempt to inspect the internal events object using jQuery.data, + // it is undocumented and subject to change. But does anyone listen? No. + if ( isEvents && !thisCache[ name ] ) { + return privateCache.events; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, l, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ internalKey ] : internalKey; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split( " " ); + } + } + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the cache and need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ internalKey ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( internalKey ); + } else { + elem[ internalKey ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var parts, part, attr, name, l, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attr = elem.attributes; + for ( l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + parts = key.split( ".", 2 ); + parts[1] = parts[1] ? "." + parts[1] : ""; + part = parts[1] + "!"; + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + data = this.triggerHandler( "getData" + part, [ parts[0] ] ); + + // Try to fetch any internally stored data first + if ( data === undefined && elem ) { + data = jQuery.data( elem, key ); + data = dataAttr( elem, key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } + + parts[1] = value; + this.each(function() { + var self = jQuery( this ); + + self.triggerHandler( "setData" + part, parts ); + jQuery.data( this, key, value ); + self.triggerHandler( "changeData" + part, parts ); + }); + }, null, value, arguments.length > 1, null, false ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + jQuery.isNumeric( data ) ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery._data( elem, deferDataKey ); + if ( defer && + ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && + ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery._data( elem, queueDataKey ) && + !jQuery._data( elem, markDataKey ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.fire(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = ( type || "fx" ) + "mark"; + jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); + if ( count ) { + jQuery._data( elem, key, count ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + var q; + if ( elem ) { + type = ( type || "fx" ) + "queue"; + q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + hooks = {}; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + jQuery._data( elem, type + ".run", hooks ); + fn.call( elem, function() { + jQuery.dequeue( elem, type ); + }, hooks ); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue " + type + ".run", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { + count++; + tmp.add( resolve ); + } + } + resolve(); + return defer.promise( object ); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + nodeHook, boolHook, fixSpecified; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + classNames = ( value || "" ).split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, i, max, option, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + i = one ? index : 0; + max = one ? index + 1 : options.length; + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, l, isBool, + i = 0; + + if ( value && elem.nodeType === 1 ) { + attrNames = value.toLowerCase().split( rspace ); + l = attrNames.length; + + for ( ; i < l; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + isBool = rboolean.test( name ); + + // See #9699 for explanation of this approach (setting first, then removal) + // Do not do this for boolean attributes (see #10870) + if ( !isBool ) { + jQuery.attr( elem, name, "" ); + } + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( isBool && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) +jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true, + coords: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.nodeValue = value + "" ); + } + }; + + // Apply the nodeHook to tabindex + jQuery.attrHooks.tabindex.set = nodeHook.set; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = "" + value ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); + + + + +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, + rhoverHack = /(?:^|\s)hover(\.\S+)?\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, + quickParse = function( selector ) { + var quick = rquickIs.exec( selector ); + if ( quick ) { + // 0 1 2 3 + // [ _, tag, id, class ] + quick[1] = ( quick[1] || "" ).toLowerCase(); + quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); + } + return quick; + }, + quickIs = function( elem, m ) { + var attrs = elem.attributes || {}; + return ( + (!m[1] || elem.nodeName.toLowerCase() === m[1]) && + (!m[2] || (attrs.id || {}).value === m[2]) && + (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) + ); + }, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, quick, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + events = elemData.events; + if ( !events ) { + elemData.events = events = {}; + } + eventHandle = elemData.handle; + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { + + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + quick: selector && quickParse( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + handlers = events[ type ]; + if ( !handlers ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + t, tns, type, origType, namespaces, origCount, + j, events, special, handle, eventType, handleObj; + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector? special.delegateType : special.bindType ) || type; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); + + if ( handleObj.selector ) { + eventType.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( eventType.length === 0 && origCount !== eventType.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, [ "events", "handle" ], true ); + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + + // Event object or event type + var type = event.type || event, + namespaces = [], + cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } + } + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + old = null; + for ( ; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old && old === elem.ownerDocument ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } + } + + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { + + cur = eventPath[i][0]; + event.type = eventPath[i][1]; + + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = [].slice.call( arguments, 0 ), + run_all = !event.exclusive && !event.namespace, + special = jQuery.event.special[ event.type ] || {}, + handlerQueue = [], + i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers that should run if there are delegated events + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !(event.button && event.type === "click") ) { + + // Pregenerate a single jQuery object for reuse with .is() + jqcur = jQuery(this); + jqcur.context = this.ownerDocument || this; + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + + // Don't process events on disabled elements (#6911, #8165) + if ( cur.disabled !== true ) { + selMatch = {}; + matches = []; + jqcur[0] = cur; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = ( + handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) + ); + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = jQuery.Event( originalEvent ); + + for ( i = copy.length; i; ) { + prop = copy[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Target should not be a text node (#504, Safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) + if ( event.metaKey === undefined ) { + event.metaKey = event.ctrlKey; + } + + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady + }, + + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector, + ret; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !form._submit_attached ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + form._submit_attached = true; + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + jQuery.event.simulate( "change", this, event, true ); + } + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + elem._change_attached = true; + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { // && selector != null + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + var handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( var type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +jQuery.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( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + expando = "sizcache" + (Math.random() + '').replace('.', ''), + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rReturn = /\r\n/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context, seed ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set, seed ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set, i, len, match, type, left; + + if ( !expr ) { + return []; + } + + for ( i = 0, len = Expr.order.length; i < len; i++ ) { + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + type, found, item, filter, left, + i, pass, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + filter = Expr.filter[ type ]; + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + pass = not ^ found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Utility function for retreiving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +var getText = Sizzle.getText = function( elem ) { + var i, node, + nodeType = elem.nodeType, + ret = ""; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent || innerText for elements + if ( typeof elem.textContent === 'string' ) { + return elem.textContent; + } else if ( typeof elem.innerText === 'string' ) { + // Replace IE's carriage returns + return elem.innerText.replace( rReturn, '' ); + } else { + // Traverse it's children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + } else { + + // If no nodeType, this is expected to be an array + for ( i = 0; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + if ( node.nodeType !== 8 ) { + ret += getText( node ); + } + } + } + return ret; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + selected: function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var first, last, + doneName, parent, cache, + count, diff, + type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + /* falls through */ + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + first = match[2]; + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + doneName = match[0]; + parent = elem.parentNode; + + if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { + count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent[ expando ] = doneName; + } + + diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Sizzle.attr ? + Sizzle.attr( elem, name ) : + Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + !type && Sizzle.attr ? + result != null : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} +// Expose origPOS +// "global" as in regardless of relation to brackets/parens +Expr.match.globalPOS = origPOS; + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

    "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id === match[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
    "; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context, seed ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet, seed ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +Sizzle.selectors.attrMap = {}; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.globalPOS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + POS.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array (deprecated as of jQuery 1.7) + if ( jQuery.isArray( selectors ) ) { + var level = 1; + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( i = 0; i < selectors.length; i++ ) { + + if ( jQuery( cur ).is( selectors[ i ] ) ) { + ret.push({ selector: selectors[ i ], elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, slice.call( arguments ).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} + + + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /]", "i"), + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /\/(java|ecma)script/i, + rcleanScript = /^\s*", "" ], + legend: [ 1, "
    ", "
    " ], + thead: [ 1, "", "
    " ], + tr: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + col: [ 2, "", "
    " ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }, + safeFragment = createSafeFragment( document ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + + + + + + + +
    +
    + + + + + +
    +
    + +
    +
    +
    +
    + + +

    Index

    + +
    + A + | B + | C + | D + | E + | F + | G + | H + | I + | J + | K + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + | X + +
    +

    A

    + + + +
    + +
    abort (nepi.execution.ec.ExperimentController attribute) +
    + +
    + +
    (nepi.execution.ec.FailureManager attribute) +
    + +
    + +
    add_edge() (nepi.util.netgraph.NetGraph method) +
    + + +
    add_node() (nepi.util.netgraph.NetGraph method) +
    + + +
    add_resource_to_slice() (nepi.util.manifoldapi.MANIFOLDAPI method) +
    + +
    + +
    (nepi.util.sfaapi.SFAAPI method) +
    + +
    + +
    add_resource_to_slice_batch() (nepi.util.sfaapi.SFAAPI method) +
    + + +
    add_set_hook() (nepi.resources.omf.application.OMFApplication method) +
    + + +
    add_set_hooks() (nepi.resources.linux.interface.LinuxInterface method) +
    + + +
    add_slice_nodes() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    ADHOC (nepi.util.netgraph.TopologyType attribute) +
    + + +
    alias_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
    + + +
    ALL (nepi.execution.trace.TraceAttr attribute) +
    + + +
    allowed (nepi.execution.attribute.Attribute attribute) +
    + + +
    allowed_types (nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
    + + +
    AMtoGateway (nepi.resources.omf.omf_resource.ResourceGateway attribute) +
    + + +
    annotate_cn_graph() (in module nepi.data.processing.ccn.parser) +
    + +
    + +
    (in module nepi.data.processing.ping.parser) +
    + +
    +
    + +
    annotate_cn_node() (in module nepi.data.processing.ccn.parser) +
    + +
    + +
    (in module nepi.data.processing.ping.parser) +
    + +
    + +
    annotate_edge() (nepi.util.netgraph.NetGraph method) +
    + + +
    annotate_edge_net() (nepi.util.netgraph.NetGraph method) +
    + + +
    annotate_node() (nepi.util.netgraph.NetGraph method) +
    + + +
    annotate_node_ip() (nepi.util.netgraph.NetGraph method) +
    + + +
    api (nepi.resources.planetlab.plcapi.PLCAPI attribute) +
    + +
    + +
    (nepi.util.manifoldapi.MANIFOLDAPI attribute) +
    + +
    + +
    app_home (nepi.resources.linux.application.LinuxApplication attribute) +
    + + +
    app_home() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + +
    + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + +
    + +
    arp (nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
    + + +
    ascii_helper_uuid (nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice attribute) +
    + + +
    assign_controller() (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
    + + +
    assign_p2p_ips() (nepi.util.netgraph.NetGraph method) +
    + + +
    attach() (nepi.util.parallel.WorkerThread method) +
    + + +
    Attribute (class in nepi.execution.attribute) +
    + +
    + +

    B

    + + + +
    + +
    backticks() (in module nepi.util.environ) +
    + + +
    BaseOMFClient (class in nepi.resources.omf.omf_client) +
    + + +
    bin_dir (nepi.resources.linux.node.LinuxNode attribute) +
    + + +
    blacklist_host() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    blacklist_resource() (nepi.util.sfaapi.SFAAPI method) +
    + +
    + +
    blacklisted() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + +
    + +
    (nepi.util.sfaapi.SFAAPI method) +
    + +
    + +
    Bool (nepi.execution.attribute.Types attribute) +
    + + +
    build() (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    build_sfa_rspec() (nepi.util.sfarspec_proc.SfaRSpecProcessing method) +
    + +
    + +

    C

    + + + +
    + +
    ccn_client_helper_uuid (nepi.resources.ns3.ns3ccndceapplication.NS3BaseCCNDceApplication attribute) +
    + + +
    ccn_client_lock (nepi.resources.ns3.ns3ccndceapplication.NS3BaseCCNDceApplication attribute) +
    + + +
    ccn_consumers() (in module nepi.data.processing.ccn.parser) +
    + + +
    ccn_producers() (in module nepi.data.processing.ccn.parser) +
    + + +
    ccnd (nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication attribute) +
    + +
    + +
    (nepi.resources.linux.ccn.ccncontent.LinuxCCNContent attribute) +
    + + +
    (nepi.resources.linux.ccn.ccnr.LinuxCCNR attribute) +
    + + +
    (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry attribute) +
    + +
    + +
    ccnpingserver (nepi.resources.linux.ccn.ccnping.LinuxCCNPing attribute) +
    + + +
    ccnr (nepi.resources.linux.ccn.ccncontent.LinuxCCNContent attribute) +
    + + +
    channel (nepi.resources.linux.interface.LinuxInterface attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice attribute) +
    + + +
    (nepi.resources.ns3.ns3propagationdelaymodel.NS3BasePropagationDelayModel attribute) +
    + + +
    (nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel attribute) +
    + + +
    (nepi.resources.ns3.ns3wifiphy.NS3BaseWifiPhy attribute) +
    + + +
    (nepi.resources.omf.interface.OMFWifiInterface attribute) +
    + +
    + +
    ChannelToFreq (nepi.resources.omf.channel.OMFChannel attribute) +
    + + +
    check_deploy() (nepi.resources.omf.application.OMFApplication method) +
    + +
    + +
    (nepi.resources.omf.interface.OMFWifiInterface method) +
    + +
    + +
    check_errors() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    check_mailbox() (nepi.resources.omf.omf6_api.OMF6API method) +
    + +
    + +
    (nepi.resources.omf.omf6_parser.OMF6Parser method) +
    + + +
    (nepi.resources.omf.omf_client.OMFClient method) +
    + +
    + +
    check_output() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    check_ready() (nepi.resources.omf.omf6_api.OMF6API method) +
    + + +
    check_release() (nepi.resources.omf.application.OMFApplication method) +
    + +
    + +
    (nepi.resources.omf.interface.OMFWifiInterface method) +
    + +
    + +
    check_sliver_ovs() (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
    + + +
    check_start() (nepi.resources.omf.application.OMFApplication method) +
    + + +
    check_state_connection() (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
    + +
    + +
    (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + + +
    (nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
    + +
    + +
    check_status() (nepi.resources.linux.tap.LinuxTap method) +
    + +
    + +
    (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
    + +
    + +
    clean_experiment() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    clean_home() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    clean_processes() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    client (nepi.resources.netns.netnsemulation.NetNSEmulation attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3simulation.NS3Simulation attribute) +
    + +
    + +
    clone_command() (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
    + + +
    close_socket() (in module nepi.resources.ns3.ns3server) +
    + + +
    clsinit() (in module nepi.execution.resource) +
    + +
    + +
    clsinit_copy() (in module nepi.execution.resource) +
    + + +
    Collector (class in nepi.resources.all.collector) +
    + + +
    compute_delay_ms() (in module nepi.util.timefuncs) +
    + + +
    compute_mean() (in module nepi.util.statfuncs) +
    + + +
    conditions (nepi.execution.resource.ResourceManager attribute) +
    + + +
    configure() (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
    + + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
    + + +
    (nepi.resources.omf.omf5_api.OMF5API method) +
    + +
    + +
    configure_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
    + +
    + +
    (nepi.resources.omf.messages_6.MessageHandler method) +
    + +
    + +
    configure_iface() (nepi.resources.omf.interface.OMFWifiInterface method) +
    + + +
    configure_ip() (nepi.resources.omf.interface.OMFWifiInterface method) +
    + + +
    configure_on_omf5() (nepi.resources.omf.interface.OMFWifiInterface method) +
    + + +
    configure_on_omf6() (nepi.resources.omf.interface.OMFWifiInterface method) +
    + + +
    connected (nepi.resources.netns.netnsbase.NetNSBase attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3base.NS3Base attribute) +
    + +
    + +
    connections (nepi.execution.resource.ResourceManager attribute) +
    + + +
    Construct (nepi.execution.attribute.Flags attribute) +
    + + +
    copy() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    CORRUPTFILE (nepi.resources.linux.node.ExitCode attribute) +
    + + +
    CREATE (nepi.resources.netns.netnsserver.NetNSWrapperMessage attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
    + +
    + +
    create() (nepi.execution.resource.ResourceFactory class method) +
    + +
    + +
    (nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
    + + +
    (nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
    + + +
    (nepi.resources.netns.netnsclient.NetNSClient method) +
    + + +
    (nepi.resources.netns.netnsemulation.NetNSEmulation method) +
    + + +
    (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
    + + +
    (nepi.resources.ns3.ns3client.NS3Client method) +
    + + +
    (nepi.resources.ns3.ns3simulation.NS3Simulation method) +
    + + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
    + + +
    (nepi.resources.omf.omf_client.OMFClient method) +
    + +
    + +
    create_and_enroll_topic() (nepi.resources.omf.omf6_api.OMF6API method) +
    + + +
    create_api() (nepi.resources.omf.omf_api_factory.OMFAPIFactory class method) +
    + +
    + +
    (nepi.resources.planetlab.plcapi.PLCAPIFactory class method) +
    + +
    + +
    create_bridge() (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
    + + +
    create_function() (nepi.resources.omf.messages_6.MessageHandler method) +
    + + +
    create_ns3_rms() (in module nepi.resources.ns3.resource_manager_generator) +
    + + +
    create_port() (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
    + + +
    create_socket() (in module nepi.resources.netns.netnsserver) +
    + + +
    Credential (nepi.execution.attribute.Flags attribute) +
    + +
    + +

    D

    + + + +
    + +
    dce_application_lock (nepi.resources.ns3.ns3dcehelper.NS3DceHelper attribute) +
    + + +
    dce_application_uuid (nepi.resources.ns3.ns3dcehelper.NS3DceHelper attribute) +
    + + +
    dce_helper (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
    + + +
    dce_manager_lock (nepi.resources.ns3.ns3dcehelper.NS3DceHelper attribute) +
    + + +
    dce_manager_uuid (nepi.resources.ns3.ns3dcehelper.NS3DceHelper attribute) +
    + + +
    dce_repo (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
    + + +
    dce_src_location (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
    + + +
    dce_version (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
    + + +
    dceapplications (nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
    + + +
    DEBIAN (nepi.resources.linux.node.OSType attribute) +
    + + +
    debug() (nepi.util.logger.Logger method) +
    + + +
    debuger (nepi.resources.netns.netnswrapper.NetNSWrapper attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
    + +
    + +
    default (nepi.execution.attribute.Attribute attribute) +
    + + +
    del_edge_annotation() (nepi.util.netgraph.NetGraph method) +
    + + +
    del_node_annotation() (nepi.util.netgraph.NetGraph method) +
    + + +
    delete() (nepi.resources.omf.omf5_api.OMF5API method) +
    + +
    + +
    (nepi.resources.omf.omf_client.OMFClient method) +
    + +
    + +
    delete_slice_node() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    DEPLOY (nepi.execution.resource.ResourceAction attribute) +
    + + +
    deploy() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    deploy_with_conditions() (nepi.execution.resource.ResourceManager method) +
    + + +
    Design (nepi.execution.attribute.Flags attribute) +
    + + +
    destroy() (nepi.util.parallel.ParallelRun method) +
    + + +
    device (nepi.resources.linux.route.LinuxRoute attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel attribute) +
    + + +
    (nepi.resources.ns3.ns3queue.NS3BaseQueue attribute) +
    + + +
    (nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac attribute) +
    + + +
    (nepi.resources.ns3.ns3wifiphy.NS3BaseWifiPhy attribute) +
    + + +
    (nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager attribute) +
    + +
    + +
    device_helper_uuid (nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice attribute) +
    + + +
    devices (nepi.resources.ns3.ns3channel.NS3BaseChannel attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
    + + +
    (nepi.resources.ns3.ns3pipechanel.NS3BasePipeChannel attribute) +
    + +
    + +
    disconnect() (nepi.resources.omf.omf5_api.OMF5API method) +
    + +
    + +
    (nepi.resources.omf.omf6_api.OMF6API method) +
    + +
    + +
    discover() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    discover_time (nepi.execution.resource.ResourceManager attribute) +
    + +
    + +
    DISCOVERED (nepi.execution.resource.ResourceState attribute) +
    + + +
    do_configure() (nepi.execution.resource.ResourceManager method) +
    + + +
    do_connect() (nepi.execution.resource.ResourceManager method) +
    + + +
    do_deploy() (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    (nepi.resources.all.collector.Collector method) +
    + + +
    (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    (nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication method) +
    + + +
    (nepi.resources.linux.ccn.ccncat.LinuxCCNCat method) +
    + + +
    (nepi.resources.linux.ccn.ccncontent.LinuxCCNContent method) +
    + + +
    (nepi.resources.linux.ccn.ccnd.LinuxCCND method) +
    + + +
    (nepi.resources.linux.ccn.ccnpeek.LinuxCCNPeek method) +
    + + +
    (nepi.resources.linux.ccn.ccnpingserver.LinuxCCNPingServer method) +
    + + +
    (nepi.resources.linux.ccn.ccnpoke.LinuxCCNPoke method) +
    + + +
    (nepi.resources.linux.ccn.ccnr.LinuxCCNR method) +
    + + +
    (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
    + + +
    (nepi.resources.linux.interface.LinuxInterface method) +
    + + +
    (nepi.resources.linux.mtr.LinuxMtr method) +
    + + +
    (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
    + + +
    (nepi.resources.linux.node.LinuxNode method) +
    + + +
    (nepi.resources.linux.nping.LinuxNPing method) +
    + + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
    + + +
    (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink method) +
    + + +
    (nepi.resources.linux.ping.LinuxPing method) +
    + + +
    (nepi.resources.linux.route.LinuxRoute method) +
    + + +
    (nepi.resources.linux.tap.LinuxTap method) +
    + + +
    (nepi.resources.linux.tcpdump.LinuxTcpdump method) +
    + + +
    (nepi.resources.linux.traceroute.LinuxTraceroute method) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + + +
    (nepi.resources.linux.udptest.LinuxUdpTest method) +
    + + +
    (nepi.resources.netns.netnsbase.NetNSBase method) +
    + + +
    (nepi.resources.ns3.ns3base.NS3Base method) +
    + + +
    (nepi.resources.omf.application.OMFApplication method) +
    + + +
    (nepi.resources.omf.channel.OMFChannel method) +
    + + +
    (nepi.resources.omf.interface.OMFWifiInterface method) +
    + + +
    (nepi.resources.omf.node.OMFNode method) +
    + + +
    (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
    + + +
    (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
    + + +
    (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
    + + +
    (nepi.resources.planetlab.vroute.PlanetlabVroute method) +
    + +
    + +
    do_disconnect() (nepi.execution.resource.ResourceManager method) +
    + + +
    do_discover() (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    (nepi.resources.linux.interface.LinuxInterface method) +
    + + +
    (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
    + + +
    (nepi.resources.planetlab.node.PlanetlabNode method) +
    + + +
    (nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
    + +
    + +
    do_fail() (nepi.execution.resource.ResourceManager method) +
    + + +
    do_provision() (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    (nepi.resources.all.collector.Collector method) +
    + + +
    (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    (nepi.resources.linux.interface.LinuxInterface method) +
    + + +
    (nepi.resources.linux.node.LinuxNode method) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + + +
    (nepi.resources.netns.netnsbase.NetNSBase method) +
    + + +
    (nepi.resources.ns3.ns3base.NS3Base method) +
    + + +
    (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
    + + +
    (nepi.resources.planetlab.node.PlanetlabNode method) +
    + + +
    (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
    + + +
    (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
    + + +
    (nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
    + +
    + +
    do_release() (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    (nepi.resources.all.collector.Collector method) +
    + + +
    (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    (nepi.resources.linux.interface.LinuxInterface method) +
    + + +
    (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
    + + +
    (nepi.resources.linux.node.LinuxNode method) +
    + + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
    + + +
    (nepi.resources.linux.tap.LinuxTap method) +
    + + +
    (nepi.resources.omf.application.OMFApplication method) +
    + + +
    (nepi.resources.omf.channel.OMFChannel method) +
    + + +
    (nepi.resources.omf.interface.OMFWifiInterface method) +
    + + +
    (nepi.resources.omf.node.OMFNode method) +
    + + +
    (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
    + + +
    (nepi.resources.planetlab.node.PlanetlabNode method) +
    + + +
    (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
    + + +
    (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
    + + +
    (nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
    + + +
    (nepi.resources.planetlab.vroute.PlanetlabVroute method) +
    + +
    + +
    do_reserve() (nepi.execution.resource.ResourceManager method) +
    + + +
    do_start() (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    (nepi.resources.linux.ccn.ccncontent.LinuxCCNContent method) +
    + + +
    (nepi.resources.linux.ccn.ccnd.LinuxCCND method) +
    + + +
    (nepi.resources.linux.ccn.ccnping.LinuxCCNPing method) +
    + + +
    (nepi.resources.linux.ccn.ccnr.LinuxCCNR method) +
    + + +
    (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
    + + +
    (nepi.resources.linux.mtr.LinuxMtr method) +
    + + +
    (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
    + + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
    + + +
    (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink method) +
    + + +
    (nepi.resources.linux.ping.LinuxPing method) +
    + + +
    (nepi.resources.linux.route.LinuxRoute method) +
    + + +
    (nepi.resources.linux.tap.LinuxTap method) +
    + + +
    (nepi.resources.linux.traceroute.LinuxTraceroute method) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + + +
    (nepi.resources.linux.udptest.LinuxUdpTest method) +
    + + +
    (nepi.resources.netns.netnsapplication.NetNSApplication method) +
    + + +
    (nepi.resources.netns.netnsbase.NetNSBase method) +
    + + +
    (nepi.resources.ns3.ns3application.NS3BaseApplication method) +
    + + +
    (nepi.resources.ns3.ns3base.NS3Base method) +
    + + +
    (nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication method) +
    + + +
    (nepi.resources.omf.application.OMFApplication method) +
    + + +
    (nepi.resources.planetlab.vroute.PlanetlabVroute method) +
    + +
    + +
    do_stop() (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    (nepi.resources.linux.ccn.ccnd.LinuxCCND method) +
    + + +
    (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
    + + +
    (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
    + + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
    + + +
    (nepi.resources.linux.route.LinuxRoute method) +
    + + +
    (nepi.resources.linux.tap.LinuxTap method) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + + +
    (nepi.resources.netns.netnsbase.NetNSBase method) +
    + + +
    (nepi.resources.ns3.ns3application.NS3BaseApplication method) +
    + + +
    (nepi.resources.ns3.ns3base.NS3Base method) +
    + + +
    (nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication method) +
    + + +
    (nepi.resources.omf.application.OMFApplication method) +
    + + +
    (nepi.resources.planetlab.vroute.PlanetlabVroute method) +
    + +
    + +
    DONE (nepi.execution.scheduler.TaskStatus attribute) +
    + + +
    DOT (nepi.util.plotter.PFormats attribute) +
    + + +
    Double (nepi.execution.attribute.Types attribute) +
    + + +
    download() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    dump_content_history() (in module nepi.data.processing.ccn.parser) +
    + + +
    dump_create() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + +
    + +
    dump_factory() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + +
    + +
    dump_get() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + +
    + +
    dump_header() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + +
    + +
    dump_invoke() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + +
    + +
    dump_set() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + +
    + +
    dump_shutdown() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + +
    + +
    dump_start() (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + + +
    dump_stop() (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + + +
    dump_to_script() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + +
    +
    + +

    E

    + + + +
    + +
    ec (nepi.execution.ec.FailureManager attribute) +
    + +
    + +
    (nepi.execution.resource.ResourceManager attribute) +
    + +
    + +
    EC_FAILURE (nepi.execution.ec.FailureLevel attribute) +
    + + +
    ECPlotter (class in nepi.util.plotter) +
    + + +
    ECSerializer (class in nepi.util.serializer) +
    + + +
    ECState (class in nepi.execution.ec) +
    + + +
    ecstate (nepi.execution.ec.ExperimentController attribute) +
    + + +
    ECXMLParser (class in nepi.util.parsers.xml_parser) +
    + + +
    edge_annotation() (nepi.util.netgraph.NetGraph method) +
    + + +
    edge_annotations() (nepi.util.netgraph.NetGraph method) +
    + + +
    edge_net_annotation() (nepi.util.netgraph.NetGraph method) +
    + + +
    edges() (nepi.util.netgraph.NetGraph method) +
    + + +
    eintr_retry() (in module nepi.util.sshfuncs) +
    + + +
    empty() (nepi.util.parallel.ParallelRun method) +
    + + +
    emu_get() (nepi.resources.netns.netnsemulation.NetNSEmulation method) +
    + + +
    emu_set() (nepi.resources.netns.netnsemulation.NetNSEmulation method) +
    + + +
    emulation (nepi.resources.linux.netns.netnsclient.LinuxNetNSClient attribute) +
    + +
    + +
    (nepi.resources.netns.netnsapplication.NetNSApplication attribute) +
    + + +
    (nepi.resources.netns.netnsipv4address.NetNSIPv4Address attribute) +
    + + +
    (nepi.resources.netns.netnsnode.NetNSNode attribute) +
    + + +
    (nepi.resources.netns.netnsnodeinterface.NetNSNodeInterface attribute) +
    + + +
    (nepi.resources.netns.netnsroute.NetNSIPv4Route attribute) +
    + + +
    (nepi.resources.netns.netnsswitch.NetNSSwitch attribute) +
    + +
    + +
    enable_dce (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
    + + +
    enable_trace() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    enabled (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger attribute) +
    + +
    + +
    endpoint1 (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel attribute) +
    + +
    + +
    (nepi.resources.linux.tunnel.LinuxTunnel attribute) +
    + +
    + +
    endpoint2 (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel attribute) +
    + +
    + +
    (nepi.resources.linux.tunnel.LinuxTunnel attribute) +
    + +
    + +
    endpoint_mkdir() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + +
    + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + +
    + +
    endpoint_node() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    enroll_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
    + +
    + +
    enroll_host() (nepi.resources.omf.omf5_api.OMF5API method) +
    + + +
    enroll_topic() (nepi.resources.omf.omf6_api.OMF6API method) +
    + + +
    Enumerate (nepi.execution.attribute.Types attribute) +
    + + +
    ERROR (nepi.execution.scheduler.TaskStatus attribute) +
    + +
    + +
    (nepi.resources.linux.node.ExitCode attribute) +
    + +
    + +
    error() (nepi.util.logger.Logger method) +
    + + +
    establish() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    establish_connection() (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
    + +
    + +
    (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + + +
    (nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
    + +
    + +
    establish_udp_connection() (nepi.resources.linux.tap.LinuxTap method) +
    + +
    + +
    (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
    + +
    + +
    eval_failure() (nepi.execution.ec.FailureManager method) +
    + + +
    evaluate_normal_convergence() (nepi.execution.runner.ExperimentRunner method) +
    + + +
    execute() (in module nepi.util.environ) +
    + +
    + +
    (nepi.resources.linux.node.LinuxNode method) +
    + + +
    (nepi.resources.omf.omf5_api.OMF5API method) +
    + + +
    (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
    + +
    + +
    execute_command() (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    execute_deploy_command() (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    execute_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
    + + +
    exit() (nepi.resources.omf.omf5_api.OMF5API method) +
    + + +
    exit_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
    + + +
    ExitCode (class in nepi.resources.linux.node) +
    + + +
    exitcode() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    exp_dir (nepi.execution.ec.ExperimentController attribute) +
    + +
    + +
    (nepi.resources.linux.node.LinuxNode attribute) +
    + +
    + +
    exp_home (nepi.resources.linux.node.LinuxNode attribute) +
    + + +
    exp_id (nepi.execution.ec.ExperimentController attribute) +
    + +
    + +
    (nepi.resources.omf.application.OMFApplication attribute) +
    + + +
    (nepi.resources.omf.channel.OMFChannel attribute) +
    + + +
    (nepi.resources.omf.interface.OMFWifiInterface attribute) +
    + + +
    (nepi.resources.omf.node.OMFNode attribute) +
    + +
    + +
    ExperimentController (class in nepi.execution.ec) +
    + + +
    ExperimentRunner (class in nepi.execution.runner) +
    + +
    + +

    F

    + + + +
    + +
    FACTORY (nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
    + + +
    factory() (nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
    + +
    + +
    (nepi.resources.ns3.ns3client.NS3Client method) +
    + + +
    (nepi.resources.ns3.ns3simulation.NS3Simulation method) +
    + + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
    + +
    + +
    fail() (nepi.execution.resource.ResourceManager method) +
    + + +
    fail_discovery() (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
    + +
    + +
    (nepi.resources.planetlab.node.PlanetlabNode method) +
    + + +
    (nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
    + +
    + +
    fail_node_not_alive() (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
    + +
    + +
    (nepi.resources.planetlab.node.PlanetlabNode method) +
    + + +
    (nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
    + +
    + +
    fail_node_not_available() (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
    + +
    + +
    (nepi.resources.planetlab.node.PlanetlabNode method) +
    + + +
    (nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
    + +
    + +
    fail_not_enough_nodes() (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
    + +
    + +
    (nepi.resources.planetlab.node.PlanetlabNode method) +
    + + +
    (nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
    + +
    + +
    fail_plapi() (nepi.resources.planetlab.node.PlanetlabNode method) +
    + + +
    fail_sfaapi() (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
    + +
    + +
    (nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
    + +
    + +
    FAILED (nepi.execution.ec.ECState attribute) +
    + +
    + +
    (nepi.execution.resource.ResourceState attribute) +
    + +
    + +
    failed_time (nepi.execution.resource.ResourceManager attribute) +
    + + +
    failtrap() (in module nepi.execution.resource) +
    + + +
    failure_level (nepi.execution.ec.ExperimentController attribute) +
    + + +
    FailureLevel (class in nepi.execution.ec) +
    + + +
    FailureManager (class in nepi.execution.ec) +
    + + +
    fdnetdevice (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink attribute) +
    + +
    + +
    (nepi.resources.planetlab.ns3.tuntapfdlink.PlanetlabTunTapFdLink attribute) +
    + +
    + +
    fdnode (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink attribute) +
    + + +
    FEDORA (nepi.resources.linux.node.OSType attribute) +
    + + +
    FEDORA_12 (nepi.resources.linux.node.OSType attribute) +
    + + +
    FEDORA_14 (nepi.resources.linux.node.OSType attribute) +
    + + +
    FEDORA_8 (nepi.resources.linux.node.OSType attribute) +
    + + +
    FIGURE (nepi.util.plotter.PFormats attribute) +
    + + +
    FILENOTFOUND (nepi.resources.linux.node.ExitCode attribute) +
    + + +
    Filter (nepi.execution.attribute.Flags attribute) +
    + +
    + +
    filter_existing_files() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    filter_resources() (nepi.execution.ec.ExperimentController method) +
    + + +
    find_boxes() (in module nepi.util.rmatcher) +
    + + +
    find_home() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    find_types() (in module nepi.execution.resource) +
    + + +
    finish_multicall() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    FINISHED (nepi.util.sshfuncs.ProcStatus attribute) +
    + + +
    Flags (class in nepi.execution.attribute) +
    + + +
    flags (nepi.execution.attribute.Attribute attribute) +
    + + +
    FLUSH (nepi.resources.netns.netnsserver.NetNSWrapperMessage attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
    + +
    + +
    flush() (nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
    + +
    + +
    (nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
    + + +
    (nepi.resources.netns.netnsclient.NetNSClient method) +
    + + +
    (nepi.resources.netns.netnsemulation.NetNSEmulation method) +
    + + +
    (nepi.resources.ns3.ns3client.NS3Client method) +
    + + +
    (nepi.resources.ns3.ns3simulation.NS3Simulation method) +
    + +
    + +
    fm (nepi.execution.ec.ExperimentController attribute) +
    + + +
    format_args() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + +
    + +
    format_environment() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    format_kwargs() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + +
    + +
    format_value() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
    + +
    + +
    frcp_configure() (nepi.resources.omf.omf6_api.OMF6API method) +
    + + +
    frcp_create() (nepi.resources.omf.omf6_api.OMF6API method) +
    + + +
    frcp_inform() (nepi.resources.omf.omf6_api.OMF6API method) +
    + + +
    frcp_release() (nepi.resources.omf.omf6_api.OMF6API method) +
    + + +
    frcp_request() (nepi.resources.omf.omf6_api.OMF6API method) +
    + + +
    from_type() (in module nepi.util.parsers.xml_parser) +
    + + +
    from_xml() (nepi.util.parsers.xml_parser.ECXMLParser method) +
    + +
    + +

    G

    + + + +
    + +
    generate_topology() (nepi.util.netgraph.NetGraph method) +
    + + +
    GET (nepi.resources.netns.netnsserver.NetNSWrapperMessage attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
    + +
    + +
    get() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + + +
    (nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
    + + +
    (nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
    + + +
    (nepi.resources.netns.netnsbase.NetNSBase method) +
    + + +
    (nepi.resources.netns.netnsclient.NetNSClient method) +
    + + +
    (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
    + + +
    (nepi.resources.ns3.ns3base.NS3Base method) +
    + + +
    (nepi.resources.ns3.ns3client.NS3Client method) +
    + + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
    + + +
    (nepi.resources.omf.omf_client.OMFClient method) +
    + +
    + +
    get_api() (nepi.resources.omf.omf_api_factory.OMFAPIFactory class method) +
    + +
    + +
    (nepi.resources.planetlab.plcapi.PLCAPIFactory class method) +
    + + +
    (nepi.util.manifoldapi.MANIFOLDAPIFactory class method) +
    + + +
    (nepi.util.sfaapi.SFAAPIFactory class method) +
    + +
    + +
    get_attribute() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager class method) +
    + +
    + +
    get_attributes() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager class method) +
    + +
    + +
    get_connected() (nepi.execution.resource.ResourceManager method) +
    + + +
    get_discover_time() (nepi.execution.ec.ExperimentController method) +
    + + +
    get_endpoints() (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
    + +
    + +
    (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + + +
    (nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
    + + +
    (nepi.resources.planetlab.ns3.fdudptunnel.PlanetlabNs3FdUdpTunnel method) +
    + +
    + +
    get_failed_time() (nepi.execution.ec.ExperimentController method) +
    + + +
    get_frequency() (nepi.resources.omf.channel.OMFChannel method) +
    + + +
    get_global() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager class method) +
    + +
    + +
    get_help() (nepi.execution.resource.ResourceManager class method) +
    + + +
    get_interfaces() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    get_node_flavour() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    get_node_info() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    get_node_tags() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    get_nodes() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    get_object() (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
    + +
    + +
    get_options() (in module nepi.resources.netns.netnsserver) +
    + +
    + +
    (in module nepi.resources.ns3.ns3server) +
    + +
    + +
    get_os() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    get_p2p_info() (nepi.util.netgraph.NetGraph method) +
    + + +
    get_platform() (nepi.execution.resource.ResourceManager class method) +
    + + +
    get_provision_time() (nepi.execution.ec.ExperimentController method) +
    + + +
    get_ready_time() (nepi.execution.ec.ExperimentController method) +
    + + +
    get_release_time() (nepi.execution.ec.ExperimentController method) +
    + + +
    get_resource() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    get_resource_info() (nepi.util.manifoldapi.MANIFOLDAPI method) +
    + + +
    get_resource_type() (nepi.execution.resource.ResourceFactory class method) +
    + + +
    get_resource_urn() (nepi.util.manifoldapi.MANIFOLDAPI method) +
    + + +
    get_resources_by_type() (nepi.execution.ec.ExperimentController method) +
    + + +
    get_resources_hrn() (nepi.util.sfaapi.SFAAPI method) +
    + + +
    get_resources_info() (nepi.util.sfaapi.SFAAPI method) +
    + + +
    get_rtype() (nepi.execution.resource.ResourceManager class method) +
    + + +
    get_session_key() (nepi.util.manifoldapi.MANIFOLDAPI method) +
    + + +
    get_slice_id() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    get_slice_nodes() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    get_slice_resources() (nepi.util.manifoldapi.MANIFOLDAPI method) +
    + +
    + +
    (nepi.util.sfaapi.SFAAPI method) +
    + +
    + +
    get_slice_tags() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    get_slice_vnet_sys_tag() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    get_slices() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    get_start_time() (nepi.execution.ec.ExperimentController method) +
    + + +
    get_stop_time() (nepi.execution.ec.ExperimentController method) +
    + + +
    get_task() (nepi.execution.ec.ExperimentController method) +
    + + +
    get_traces() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager class method) +
    + +
    + +
    get_value() (nepi.execution.attribute.Attribute method) +
    + + +
    gethostbyname() (in module nepi.util.sshfuncs) +
    + + +
    getpid() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    Global (nepi.execution.attribute.Flags attribute) +
    + + +
    gre_connect() (nepi.resources.linux.tap.LinuxTap method) +
    + +
    + +
    (nepi.resources.planetlab.tap.PlanetlabTap method) +
    + +
    + +
    gre_enabled (nepi.resources.linux.tap.LinuxTap attribute) +
    + + +
    guid (nepi.execution.resource.ResourceManager attribute) +
    + + +
    GuidGenerator (class in nepi.util.guid) +
    + +
    + +

    H

    + + + +
    + +
    handle() (nepi.resources.omf.omf6_parser.OMF6Parser method) +
    + + +
    handle_message() (in module nepi.resources.netns.netnsserver) +
    + +
    + +
    (in module nepi.resources.ns3.ns3server) +
    + +
    + +
    handle_omf_message() (nepi.resources.omf.omf_client.OMFClient method) +
    + + +
    has_attribute() (nepi.execution.resource.ResourceManager method) +
    + + +
    has_changed (nepi.execution.attribute.Attribute attribute) +
    + +
    + +
    has_changed() (nepi.execution.resource.ResourceManager method) +
    + + +
    has_flag() (nepi.execution.attribute.Attribute method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    HeapScheduler (class in nepi.execution.scheduler) +
    + + +
    help (nepi.execution.attribute.Attribute attribute) +
    + +
    + +
    (nepi.execution.trace.Trace attribute) +
    + +
    + +
    home_dir (nepi.resources.linux.node.LinuxNode attribute) +
    + +
    + +

    I

    + + + +
    + +
    IFF_TAP (nepi.resources.linux.tap.LinuxTap attribute) +
    + + +
    IFF_TUN (nepi.resources.linux.tap.LinuxTap attribute) +
    + + +
    in_foreground (nepi.resources.linux.application.LinuxApplication attribute) +
    + + +
    info() (nepi.util.logger.Logger method) +
    + + +
    inform_failure() (nepi.execution.ec.ExperimentController method) +
    + + +
    init_mailbox() (nepi.resources.omf.omf6_parser.OMF6Parser method) +
    + + +
    initialize_workers() (nepi.util.parallel.ParallelRun method) +
    + + +
    initiate() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    initiate_connection() (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
    + +
    + +
    (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + + +
    (nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
    + +
    + +
    initiate_udp_connection() (nepi.resources.linux.tap.LinuxTap method) +
    + +
    + +
    (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
    + +
    + +
    install() (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    install_dependencies() (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    install_packages() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    install_packages_command() (in module nepi.resources.linux.debfuncs) +
    + +
    + +
    (in module nepi.resources.linux.rpmfuncs) +
    + + +
    (nepi.resources.linux.node.LinuxNode method) +
    + +
    + +
    install_rpmfusion_command() (in module nepi.resources.linux.rpmfuncs) +
    + +
    + +
    Integer (nepi.execution.attribute.Types attribute) +
    + + +
    interface (nepi.resources.netns.netnsipv4address.NetNSIPv4Address attribute) +
    + +
    + +
    (nepi.resources.netns.netnsswitch.NetNSSwitch attribute) +
    + +
    + +
    INVOKE (nepi.resources.netns.netnsserver.NetNSWrapperMessage attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
    + +
    + +
    invoke() (nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
    + +
    + +
    (nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
    + + +
    (nepi.resources.netns.netnsclient.NetNSClient method) +
    + + +
    (nepi.resources.netns.netnsemulation.NetNSEmulation method) +
    + + +
    (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
    + + +
    (nepi.resources.ns3.ns3client.NS3Client method) +
    + + +
    (nepi.resources.ns3.ns3simulation.NS3Simulation method) +
    + + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
    + +
    + +
    ipv4 (nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
    + + +
    is_alive() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    is_control() (in module nepi.data.processing.ccn.parser) +
    + + +
    is_finished (nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
    + + +
    is_rm_instance() (nepi.execution.resource.ResourceManager method) +
    + + +
    is_running (nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
    + + +
    is_source() (nepi.util.netgraph.NetGraph method) +
    + + +
    is_started (nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
    + + +
    is_target() (nepi.util.netgraph.NetGraph method) +
    + + +
    is_valid_value() (nepi.execution.attribute.Attribute method) +
    + +
    + +

    J

    + + +
    + +
    join() (nepi.util.parallel.ParallelRun method) +
    + +
    + +

    K

    + + +
    + +
    kill() (nepi.resources.linux.node.LinuxNode method) +
    + +
    + +

    L

    + + + +
    + +
    LADDER (nepi.util.netgraph.TopologyType attribute) +
    + + +
    lcopy() (in module nepi.util.execfuncs) +
    + + +
    lexec() (in module nepi.util.execfuncs) +
    + + +
    lgetpid() (in module nepi.util.execfuncs) +
    + + +
    lib_dir (nepi.resources.linux.node.LinuxNode attribute) +
    + + +
    LINEAR (nepi.util.netgraph.TopologyType attribute) +
    + + +
    LinuxApplication (class in nepi.resources.linux.application) +
    + + +
    LinuxCCNApplication (class in nepi.resources.linux.ccn.ccnapplication) +
    + + +
    LinuxCCNCat (class in nepi.resources.linux.ccn.ccncat) +
    + + +
    LinuxCCNContent (class in nepi.resources.linux.ccn.ccncontent) +
    + + +
    LinuxCCND (class in nepi.resources.linux.ccn.ccnd) +
    + + +
    LinuxCCNPeek (class in nepi.resources.linux.ccn.ccnpeek) +
    + + +
    LinuxCCNPing (class in nepi.resources.linux.ccn.ccnping) +
    + + +
    LinuxCCNPingServer (class in nepi.resources.linux.ccn.ccnpingserver) +
    + + +
    LinuxCCNPoke (class in nepi.resources.linux.ccn.ccnpoke) +
    + + +
    LinuxCCNR (class in nepi.resources.linux.ccn.ccnr) +
    + + +
    LinuxChannel (class in nepi.resources.linux.channel) +
    + + +
    LinuxDcePing (class in nepi.resources.linux.ns3.ns3pingdceapplication) +
    + + +
    LinuxFIBEntry (class in nepi.resources.linux.ccn.fibentry) +
    + + +
    LinuxGRETunnel (class in nepi.resources.linux.gretunnel) +
    + + +
    LinuxInterface (class in nepi.resources.linux.interface) +
    + + +
    LinuxMtr (class in nepi.resources.linux.mtr) +
    + + +
    LinuxNetNSClient (class in nepi.resources.linux.netns.netnsclient) +
    + + +
    LinuxNetNSEmulation (class in nepi.resources.linux.netns.netnsemulation) +
    + + +
    LinuxNode (class in nepi.resources.linux.node) +
    + + +
    LinuxNPing (class in nepi.resources.linux.nping) +
    + + +
    LinuxNS3CCNDceApplication (class in nepi.resources.linux.ns3.ccn.ns3ccndceapplication) +
    + + +
    LinuxNS3Client (class in nepi.resources.linux.ns3.ns3client) +
    + + +
    LinuxNS3DceApplication (class in nepi.resources.linux.ns3.ns3dceapplication) +
    + + +
    LinuxNS3DceCCNCat (class in nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication) +
    + + +
    LinuxNS3DceCCND (class in nepi.resources.linux.ns3.ccn.ns3ccnddceapplication) +
    + + +
    LinuxNS3DceCCNPeek (class in nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication) +
    + +
    + +
    LinuxNS3DceCCNPoke (class in nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication) +
    + + +
    LinuxNS3DceCCNR (class in nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication) +
    + + +
    LinuxNS3DceFIBEntry (class in nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication) +
    + + +
    LinuxNs3FdUdpTunnel (class in nepi.resources.linux.ns3.fdudptunnel) +
    + + +
    LinuxNS3Simulation (class in nepi.resources.linux.ns3.ns3simulation) +
    + + +
    LinuxPing (class in nepi.resources.linux.ping) +
    + + +
    LinuxRoute (class in nepi.resources.linux.route) +
    + + +
    LinuxTap (class in nepi.resources.linux.tap) +
    + + +
    LinuxTcpdump (class in nepi.resources.linux.tcpdump) +
    + + +
    LinuxTraceroute (class in nepi.resources.linux.traceroute) +
    + + +
    LinuxTun (class in nepi.resources.linux.tun) +
    + + +
    LinuxTunnel (class in nepi.resources.linux.tunnel) +
    + + +
    LinuxTunTapFdLink (class in nepi.resources.linux.ns3.tuntapfdlink) +
    + + +
    LinuxUdpTest (class in nepi.resources.linux.udptest) +
    + + +
    LinuxUdpTunnel (class in nepi.resources.linux.udptunnel) +
    + + +
    lkill() (in module nepi.util.execfuncs) +
    + + +
    load() (nepi.execution.ec.ExperimentController class method) +
    + +
    + +
    (nepi.util.serializer.ECSerializer method) +
    + +
    + +
    load_configuration() (nepi.resources.linux.interface.LinuxInterface method) +
    + + +
    load_content_history() (in module nepi.data.processing.ccn.parser) +
    + + +
    load_ns3_libraries() (in module nepi.resources.ns3.ns3wrapper) +
    + + +
    load_ns3_module() (in module nepi.resources.ns3.ns3wrapper) +
    + + +
    local_dir (nepi.execution.ec.ExperimentController attribute) +
    + + +
    localhost (nepi.resources.linux.node.LinuxNode attribute) +
    + + +
    lock (nepi.resources.omf.omf_api_factory.OMFAPIFactory attribute) +
    + +
    + +
    (nepi.resources.planetlab.node.PlanetlabNode attribute) +
    + +
    + +
    log() (in module nepi.util.sshfuncs) +
    + +
    + +
    (nepi.util.logger.Logger method) +
    + +
    + +
    log_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
    + + +
    log_message() (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    (nepi.resources.linux.channel.LinuxChannel method) +
    + + +
    (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
    + + +
    (nepi.resources.linux.interface.LinuxInterface method) +
    + + +
    (nepi.resources.linux.node.LinuxNode method) +
    + + +
    (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + + +
    (nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
    + + +
    (nepi.util.logger.Logger method) +
    + +
    + +
    Logger (class in nepi.util.logger) +
    + + +
    logger (nepi.execution.ec.ExperimentController attribute) +
    + +
    + +
    (nepi.resources.netns.netnswrapper.NetNSWrapper attribute) +
    + + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
    + + +
    (nepi.util.logger.Logger attribute) +
    + +
    + +
    lspawn() (in module nepi.util.execfuncs) +
    + + +
    lstatus() (in module nepi.util.execfuncs) +
    + +
    + +

    M

    + + + +
    + +
    make_control_path() (in module nepi.util.sshfuncs) +
    + + +
    make_dict_rec() (nepi.util.sfarspec_proc.SfaRSpecProcessing method) +
    + + +
    make_key() (nepi.util.manifoldapi.MANIFOLDAPIFactory class method) +
    + +
    + +
    (nepi.util.sfaapi.SFAAPIFactory class method) +
    + +
    + +
    make_server_key_args() (in module nepi.util.sshfuncs) +
    + + +
    make_uuid() (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
    + +
    + +
    MANIFOLDAPI (class in nepi.util.manifoldapi) +
    + + +
    MANIFOLDAPIFactory (class in nepi.util.manifoldapi) +
    + +
    + +
    match_tags() (in module nepi.util.rmatcher) +
    + + +
    mcapi (nepi.resources.planetlab.plcapi.PLCAPI attribute) +
    + + +
    MESH (nepi.util.netgraph.TopologyType attribute) +
    + + +
    MessageHandler (class in nepi.resources.omf.messages_5_4) +
    + +
    + +
    (class in nepi.resources.omf.messages_6) +
    + +
    + +
    mkdir() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    mobility (nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
    + +
    + +

    N

    + + + +
    + +
    name (nepi.execution.attribute.Attribute attribute) +
    + +
    + +
    (nepi.execution.trace.Trace attribute) +
    + +
    + +
    nepi (module) +
    + + +
    nepi.data (module) +
    + + +
    nepi.data.processing (module) +
    + + +
    nepi.data.processing.ccn (module) +
    + + +
    nepi.data.processing.ccn.parser (module) +
    + + +
    nepi.data.processing.ping (module) +
    + + +
    nepi.data.processing.ping.parser (module) +
    + + +
    nepi.execution (module) +
    + + +
    nepi.execution.attribute (module) +
    + + +
    nepi.execution.ec (module) +
    + + +
    nepi.execution.resource (module) +
    + + +
    nepi.execution.runner (module) +
    + + +
    nepi.execution.scheduler (module) +
    + + +
    nepi.execution.tags (module) +
    + + +
    nepi.execution.trace (module) +
    + + +
    nepi.resources (module) +
    + + +
    nepi.resources.all (module) +
    + + +
    nepi.resources.all.collector (module) +
    + + +
    nepi.resources.linux (module) +
    + + +
    nepi.resources.linux.application (module) +
    + + +
    nepi.resources.linux.ccn (module) +
    + + +
    nepi.resources.linux.ccn.ccnapplication (module) +
    + + +
    nepi.resources.linux.ccn.ccncat (module) +
    + + +
    nepi.resources.linux.ccn.ccncontent (module) +
    + + +
    nepi.resources.linux.ccn.ccnd (module) +
    + + +
    nepi.resources.linux.ccn.ccnpeek (module) +
    + + +
    nepi.resources.linux.ccn.ccnping (module) +
    + + +
    nepi.resources.linux.ccn.ccnpingserver (module) +
    + + +
    nepi.resources.linux.ccn.ccnpoke (module) +
    + + +
    nepi.resources.linux.ccn.ccnr (module) +
    + + +
    nepi.resources.linux.ccn.fibentry (module) +
    + + +
    nepi.resources.linux.channel (module) +
    + + +
    nepi.resources.linux.debfuncs (module) +
    + + +
    nepi.resources.linux.gretunnel (module) +
    + + +
    nepi.resources.linux.interface (module) +
    + + +
    nepi.resources.linux.mtr (module) +
    + + +
    nepi.resources.linux.netns (module) +
    + + +
    nepi.resources.linux.netns.netnsclient (module) +
    + + +
    nepi.resources.linux.netns.netnsemulation (module) +
    + + +
    nepi.resources.linux.node (module) +
    + + +
    nepi.resources.linux.nping (module) +
    + + +
    nepi.resources.linux.ns3 (module) +
    + + +
    nepi.resources.linux.ns3.ccn (module) +
    + + +
    nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication (module) +
    + + +
    nepi.resources.linux.ns3.ccn.ns3ccndceapplication (module) +
    + + +
    nepi.resources.linux.ns3.ccn.ns3ccnddceapplication (module) +
    + + +
    nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication (module) +
    + + +
    nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication (module) +
    + + +
    nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication (module) +
    + + +
    nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication (module) +
    + + +
    nepi.resources.linux.ns3.fdudptunnel (module) +
    + + +
    nepi.resources.linux.ns3.ns3client (module) +
    + + +
    nepi.resources.linux.ns3.ns3dceapplication (module) +
    + + +
    nepi.resources.linux.ns3.ns3pingdceapplication (module) +
    + + +
    nepi.resources.linux.ns3.ns3simulation (module) +
    + + +
    nepi.resources.linux.ns3.tuntapfdlink (module) +
    + + +
    nepi.resources.linux.ping (module) +
    + + +
    nepi.resources.linux.route (module) +
    + + +
    nepi.resources.linux.rpmfuncs (module) +
    + + +
    nepi.resources.linux.tap (module) +
    + + +
    nepi.resources.linux.tcpdump (module) +
    + + +
    nepi.resources.linux.traceroute (module) +
    + + +
    nepi.resources.linux.tun (module) +
    + + +
    nepi.resources.linux.tunnel (module) +
    + + +
    nepi.resources.linux.udptest (module) +
    + + +
    nepi.resources.linux.udptunnel (module) +
    + + +
    nepi.resources.netns (module) +
    + + +
    nepi.resources.netns.netnsapplication (module) +
    + + +
    nepi.resources.netns.netnsbase (module) +
    + + +
    nepi.resources.netns.netnsclient (module) +
    + + +
    nepi.resources.netns.netnsemulation (module) +
    + + +
    nepi.resources.netns.netnsinterface (module) +
    + + +
    nepi.resources.netns.netnsipv4address (module) +
    + + +
    nepi.resources.netns.netnsnode (module) +
    + + +
    nepi.resources.netns.netnsnodeinterface (module) +
    + + +
    nepi.resources.netns.netnsroute (module) +
    + + +
    nepi.resources.netns.netnsserver (module) +
    + + +
    nepi.resources.netns.netnsswitch (module) +
    + + +
    nepi.resources.netns.netnswrapper (module) +
    + + +
    nepi.resources.netns.netnswrapper_debug (module) +
    + + +
    nepi.resources.ns3 (module) +
    + + +
    nepi.resources.ns3.classes (module) +
    + + +
    nepi.resources.ns3.classes.aarf_wifi_manager (module) +
    + + +
    nepi.resources.ns3.classes.aarfcd_wifi_manager (module) +
    + + +
    nepi.resources.ns3.classes.adhoc_wifi_mac (module) +
    + + +
    nepi.resources.ns3.classes.aloha_noack_net_device (module) +
    + + +
    nepi.resources.ns3.classes.amrr_wifi_manager (module) +
    + + +
    nepi.resources.ns3.classes.ap_wifi_mac (module) +
    + + +
    nepi.resources.ns3.classes.arf_wifi_manager (module) +
    + + +
    nepi.resources.ns3.classes.arp_l3protocol (module) +
    + + +
    nepi.resources.ns3.classes.base_station_net_device (module) +
    + + +
    nepi.resources.ns3.classes.binary_error_model (module) +
    + + +
    nepi.resources.ns3.classes.binary_error_sixlow_model (module) +
    + + +
    nepi.resources.ns3.classes.bridge_channel (module) +
    + + +
    nepi.resources.ns3.classes.bridge_net_device (module) +
    + + +
    nepi.resources.ns3.classes.bulk_send_application (module) +
    + + +
    nepi.resources.ns3.classes.burst_error_model (module) +
    + + +
    nepi.resources.ns3.classes.cara_wifi_manager (module) +
    + + +
    nepi.resources.ns3.classes.constant_acceleration_mobility_model (module) +
    + + +
    nepi.resources.ns3.classes.constant_position_mobility_model (module) +
    + + +
    nepi.resources.ns3.classes.constant_rate_wifi_manager (module) +
    + + +
    nepi.resources.ns3.classes.constant_speed_propagation_delay_model (module) +
    + + +
    nepi.resources.ns3.classes.constant_velocity_mobility_model (module) +
    + + +
    nepi.resources.ns3.classes.cost231propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.csma_channel (module) +
    + + +
    nepi.resources.ns3.classes.csma_net_device (module) +
    + + +
    nepi.resources.ns3.classes.drop_tail_queue (module) +
    + + +
    nepi.resources.ns3.classes.dsrdsr_routing (module) +
    + + +
    nepi.resources.ns3.classes.emu_net_device (module) +
    + + +
    nepi.resources.ns3.classes.error_channel (module) +
    + + +
    nepi.resources.ns3.classes.error_channel_sixlow (module) +
    + + +
    nepi.resources.ns3.classes.error_net_device (module) +
    + + +
    nepi.resources.ns3.classes.fd_net_device (module) +
    + + +
    nepi.resources.ns3.classes.fixed_rss_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.friis_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.gauss_markov_mobility_model (module) +
    + + +
    nepi.resources.ns3.classes.hierarchical_mobility_model (module) +
    + + +
    nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.icmpv4l4protocol (module) +
    + + +
    nepi.resources.ns3.classes.icmpv6l4protocol (module) +
    + + +
    nepi.resources.ns3.classes.ideal_wifi_manager (module) +
    + + +
    nepi.resources.ns3.classes.ipv4l3protocol (module) +
    + + +
    nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.jakes_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.list_error_model (module) +
    + + +
    nepi.resources.ns3.classes.log_distance_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.loopback_net_device (module) +
    + + +
    nepi.resources.ns3.classes.lr_wpan_net_device (module) +
    + + +
    nepi.resources.ns3.classes.lte_enb_net_device (module) +
    + + +
    nepi.resources.ns3.classes.lte_simple_net_device (module) +
    + + +
    nepi.resources.ns3.classes.lte_ue_net_device (module) +
    + + +
    nepi.resources.ns3.classes.matrix_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.mesh_point_device (module) +
    + + +
    nepi.resources.ns3.classes.mesh_wifi_interface_mac (module) +
    + + +
    nepi.resources.ns3.classes.minstrel_wifi_manager (module) +
    + + +
    nepi.resources.ns3.classes.multi_model_spectrum_channel (module) +
    + + +
    nepi.resources.ns3.classes.nakagami_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.nist_error_rate_model (module) +
    + + +
    nepi.resources.ns3.classes.node (module) +
    + + +
    nepi.resources.ns3.classes.non_communicating_net_device (module) +
    + + +
    nepi.resources.ns3.classes.ocb_wifi_mac (module) +
    + + +
    nepi.resources.ns3.classes.oh_buildings_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.okumura_hata_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.on_off_application (module) +
    + + +
    nepi.resources.ns3.classes.onoe_wifi_manager (module) +
    + + +
    nepi.resources.ns3.classes.packet_sink (module) +
    + + +
    nepi.resources.ns3.classes.ping6 (module) +
    + + +
    nepi.resources.ns3.classes.point_to_point_channel (module) +
    + + +
    nepi.resources.ns3.classes.point_to_point_net_device (module) +
    + + +
    nepi.resources.ns3.classes.point_to_point_remote_channel (module) +
    + + +
    nepi.resources.ns3.classes.radvd (module) +
    + + +
    nepi.resources.ns3.classes.random_direction2d_mobility_model (module) +
    + + +
    nepi.resources.ns3.classes.random_propagation_delay_model (module) +
    + + +
    nepi.resources.ns3.classes.random_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.random_walk2d_mobility_model (module) +
    + + +
    nepi.resources.ns3.classes.random_waypoint_mobility_model (module) +
    + + +
    nepi.resources.ns3.classes.range_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.rate_error_model (module) +
    + + +
    nepi.resources.ns3.classes.receive_list_error_model (module) +
    + + +
    nepi.resources.ns3.classes.red_queue (module) +
    + + +
    nepi.resources.ns3.classes.rraa_wifi_manager (module) +
    + + +
    nepi.resources.ns3.classes.simple_channel (module) +
    + + +
    nepi.resources.ns3.classes.simple_net_device (module) +
    + + +
    nepi.resources.ns3.classes.single_model_spectrum_channel (module) +
    + + +
    nepi.resources.ns3.classes.six_low_pan_net_device (module) +
    + + +
    nepi.resources.ns3.classes.sta_wifi_mac (module) +
    + + +
    nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model (module) +
    + + +
    nepi.resources.ns3.classes.subscriber_station_net_device (module) +
    + + +
    nepi.resources.ns3.classes.tap_bridge (module) +
    + + +
    nepi.resources.ns3.classes.tcp_l4protocol (module) +
    + + +
    nepi.resources.ns3.classes.three_log_distance_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model (module) +
    + + +
    nepi.resources.ns3.classes.uan_channel (module) +
    + + +
    nepi.resources.ns3.classes.udp_client (module) +
    + + +
    nepi.resources.ns3.classes.udp_echo_client (module) +
    + + +
    nepi.resources.ns3.classes.udp_echo_server (module) +
    + + +
    nepi.resources.ns3.classes.udp_l4protocol (module) +
    + + +
    nepi.resources.ns3.classes.udp_server (module) +
    + + +
    nepi.resources.ns3.classes.udp_trace_client (module) +
    + + +
    nepi.resources.ns3.classes.v4ping (module) +
    + + +
    nepi.resources.ns3.classes.virtual_net_device (module) +
    + + +
    nepi.resources.ns3.classes.waypoint_mobility_model (module) +
    + + +
    nepi.resources.ns3.classes.wifi_net_device (module) +
    + + +
    nepi.resources.ns3.classes.yans_error_rate_model (module) +
    + + +
    nepi.resources.ns3.classes.yans_wifi_channel (module) +
    + + +
    nepi.resources.ns3.classes.yans_wifi_phy (module) +
    + + +
    nepi.resources.ns3.ns3application (module) +
    + + +
    nepi.resources.ns3.ns3arpl3protocol (module) +
    + + +
    nepi.resources.ns3.ns3base (module) +
    + + +
    nepi.resources.ns3.ns3ccndceapplication (module) +
    + + +
    nepi.resources.ns3.ns3channel (module) +
    + + +
    nepi.resources.ns3.ns3client (module) +
    + + +
    nepi.resources.ns3.ns3dceapplication (module) +
    + + +
    nepi.resources.ns3.ns3dcehelper (module) +
    + + +
    nepi.resources.ns3.ns3errormodel (module) +
    + + +
    nepi.resources.ns3.ns3errorratemodel (module) +
    + + +
    nepi.resources.ns3.ns3fdnetdevice (module) +
    + + +
    nepi.resources.ns3.ns3icmpv4l4protocol (module) +
    + + +
    nepi.resources.ns3.ns3ipv4l3protocol (module) +
    + + +
    nepi.resources.ns3.ns3mobilitymodel (module) +
    + + +
    nepi.resources.ns3.ns3netdevice (module) +
    + + +
    nepi.resources.ns3.ns3node (module) +
    + + +
    nepi.resources.ns3.ns3pipechanel (module) +
    + + +
    nepi.resources.ns3.ns3propagationdelaymodel (module) +
    + + +
    nepi.resources.ns3.ns3propagationlossmodel (module) +
    + + +
    nepi.resources.ns3.ns3queue (module) +
    + + +
    nepi.resources.ns3.ns3route (module) +
    + + +
    nepi.resources.ns3.ns3server (module) +
    + + +
    nepi.resources.ns3.ns3simulation (module) +
    + + +
    nepi.resources.ns3.ns3wifichannel (module) +
    + + +
    nepi.resources.ns3.ns3wifimac (module) +
    + + +
    nepi.resources.ns3.ns3wifinetdevice (module) +
    + + +
    nepi.resources.ns3.ns3wifiphy (module) +
    + + +
    nepi.resources.ns3.ns3wifiremotestationmanager (module) +
    + + +
    nepi.resources.ns3.ns3wrapper (module) +
    + + +
    nepi.resources.ns3.ns3wrapper_debug (module) +
    + + +
    nepi.resources.ns3.resource_manager_generator (module) +
    + + +
    nepi.resources.omf (module) +
    + + +
    nepi.resources.omf.application (module) +
    + +
    + +
    nepi.resources.omf.channel (module) +
    + + +
    nepi.resources.omf.interface (module) +
    + + +
    nepi.resources.omf.messages_5_4 (module) +
    + + +
    nepi.resources.omf.messages_6 (module) +
    + + +
    nepi.resources.omf.node (module) +
    + + +
    nepi.resources.omf.omf5_api (module) +
    + + +
    nepi.resources.omf.omf6_api (module) +
    + + +
    nepi.resources.omf.omf6_parser (module) +
    + + +
    nepi.resources.omf.omf_api_factory (module) +
    + + +
    nepi.resources.omf.omf_client (module) +
    + + +
    nepi.resources.omf.omf_resource (module) +
    + + +
    nepi.resources.omf.wilabt_node (module) +
    + + +
    nepi.resources.planetlab (module) +
    + + +
    nepi.resources.planetlab.node (module) +
    + + +
    nepi.resources.planetlab.ns3 (module) +
    + + +
    nepi.resources.planetlab.ns3.fdudptunnel (module) +
    + + +
    nepi.resources.planetlab.ns3.tuntapfdlink (module) +
    + + +
    nepi.resources.planetlab.openvswitch (module) +
    + + +
    nepi.resources.planetlab.openvswitch.ovs (module) +
    + + +
    nepi.resources.planetlab.openvswitch.ovsport (module) +
    + + +
    nepi.resources.planetlab.plcapi (module) +
    + + +
    nepi.resources.planetlab.sfa_node (module) +
    + + +
    nepi.resources.planetlab.tap (module) +
    + + +
    nepi.resources.planetlab.tun (module) +
    + + +
    nepi.resources.planetlab.vroute (module) +
    + + +
    nepi.util (module) +
    + + +
    nepi.util.environ (module) +
    + + +
    nepi.util.execfuncs (module) +
    + + +
    nepi.util.guid (module) +
    + + +
    nepi.util.logger (module) +
    + + +
    nepi.util.manifoldapi (module) +
    + + +
    nepi.util.netgraph (module) +
    + + +
    nepi.util.parallel (module) +
    + + +
    nepi.util.parsers (module) +
    + + +
    nepi.util.parsers.xml_parser (module) +
    + + +
    nepi.util.plotter (module) +
    + + +
    nepi.util.rmatcher (module) +
    + + +
    nepi.util.serializer (module) +
    + + +
    nepi.util.sfaapi (module) +
    + + +
    nepi.util.sfarspec_proc (module) +
    + + +
    nepi.util.sshfuncs (module) +
    + + +
    nepi.util.statfuncs (module) +
    + + +
    nepi.util.timefuncs (module) +
    + + +
    nepi_home (nepi.resources.linux.node.LinuxNode attribute) +
    + + +
    NetGraph (class in nepi.util.netgraph) +
    + + +
    netgraph (nepi.execution.ec.ExperimentController attribute) +
    + + +
    netns_repo (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
    + + +
    netns_src (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
    + + +
    netns_version (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
    + + +
    NetNSApplication (class in nepi.resources.netns.netnsapplication) +
    + + +
    NetNSBase (class in nepi.resources.netns.netnsbase) +
    + + +
    NetNSClient (class in nepi.resources.netns.netnsclient) +
    + + +
    NetNSEmulation (class in nepi.resources.netns.netnsemulation) +
    + + +
    NetNSInterface (class in nepi.resources.netns.netnsinterface) +
    + + +
    NetNSIPv4Address (class in nepi.resources.netns.netnsipv4address) +
    + + +
    NetNSIPv4Route (class in nepi.resources.netns.netnsroute) +
    + + +
    NetNSNode (class in nepi.resources.netns.netnsnode) +
    + + +
    NetNSNodeInterface (class in nepi.resources.netns.netnsnodeinterface) +
    + + +
    NetNSSwitch (class in nepi.resources.netns.netnsswitch) +
    + + +
    NetNSWrapper (class in nepi.resources.netns.netnswrapper) +
    + + +
    NetNSWrapperDebuger (class in nepi.resources.netns.netnswrapper_debug) +
    + + +
    NetNSWrapperMessage (class in nepi.resources.netns.netnsserver) +
    + + +
    network_types (nepi.resources.planetlab.plcapi.PLCAPI attribute) +
    + + +
    NEW (nepi.execution.resource.ResourceState attribute) +
    + +
    + +
    (nepi.execution.scheduler.TaskStatus attribute) +
    + +
    + +
    newexp_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
    + + +
    next() (nepi.execution.scheduler.HeapScheduler method) +
    + +
    + +
    (nepi.util.guid.GuidGenerator method) +
    + +
    + +
    node (nepi.resources.linux.application.LinuxApplication attribute) +
    + +
    + +
    (nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication attribute) +
    + + +
    (nepi.resources.linux.ccn.ccncontent.LinuxCCNContent attribute) +
    + + +
    (nepi.resources.linux.ccn.ccnr.LinuxCCNR attribute) +
    + + +
    (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry attribute) +
    + + +
    (nepi.resources.linux.interface.LinuxInterface attribute) +
    + + +
    (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink attribute) +
    + + +
    (nepi.resources.linux.route.LinuxRoute attribute) +
    + + +
    (nepi.resources.linux.tap.LinuxTap attribute) +
    + + +
    (nepi.resources.netns.netnsapplication.NetNSApplication attribute) +
    + + +
    (nepi.resources.netns.netnsipv4address.NetNSIPv4Address attribute) +
    + + +
    (nepi.resources.netns.netnsnodeinterface.NetNSNodeInterface attribute) +
    + + +
    (nepi.resources.netns.netnsroute.NetNSIPv4Route attribute) +
    + + +
    (nepi.resources.netns.netnsswitch.NetNSSwitch attribute) +
    + + +
    (nepi.resources.ns3.ns3application.NS3BaseApplication attribute) +
    + + +
    (nepi.resources.ns3.ns3arpl3protocol.NS3BaseArpL3Protocol attribute) +
    + + +
    (nepi.resources.ns3.ns3base.NS3Base attribute) +
    + + +
    (nepi.resources.ns3.ns3errorratemodel.NS3BaseErrorRateModel attribute) +
    + + +
    (nepi.resources.ns3.ns3icmpv4l4protocol.NS3BaseIcmpv4L4Protocol attribute) +
    + + +
    (nepi.resources.ns3.ns3ipv4l3protocol.NS3BaseIpv4L3Protocol attribute) +
    + + +
    (nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice attribute) +
    + + +
    (nepi.resources.ns3.ns3pipechanel.NS3BasePipeChannel attribute) +
    + + +
    (nepi.resources.ns3.ns3queue.NS3BaseQueue attribute) +
    + + +
    (nepi.resources.ns3.ns3route.NS3Route attribute) +
    + + +
    (nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac attribute) +
    + + +
    (nepi.resources.ns3.ns3wifiphy.NS3BaseWifiPhy attribute) +
    + + +
    (nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager attribute) +
    + + +
    (nepi.resources.omf.application.OMFApplication attribute) +
    + + +
    (nepi.resources.omf.interface.OMFWifiInterface attribute) +
    + + +
    (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch attribute) +
    + + +
    (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort attribute) +
    + + +
    (nepi.resources.planetlab.tap.PlanetlabTap attribute) +
    + + +
    (nepi.resources.planetlab.vroute.PlanetlabVroute attribute) +
    + +
    + +
    node1 (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel attribute) +
    + + +
    node2 (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel attribute) +
    + + +
    node_annotation() (nepi.util.netgraph.NetGraph method) +
    + + +
    node_annotations() (nepi.util.netgraph.NetGraph method) +
    + + +
    node_home (nepi.resources.linux.node.LinuxNode attribute) +
    + + +
    node_id (nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
    + + +
    node_ip_annotations() (nepi.util.netgraph.NetGraph method) +
    + + +
    nodes() (nepi.resources.omf.omf_client.OMFClient method) +
    + +
    + +
    (nepi.util.netgraph.NetGraph method) +
    + +
    + +
    noop_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
    + + +
    NoRead (nepi.execution.attribute.Flags attribute) +
    + + +
    NOT_STARTED (nepi.util.sshfuncs.ProcStatus attribute) +
    + + +
    NoWrite (nepi.execution.attribute.Flags attribute) +
    + + +
    ns3 (nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
    + + +
    ns3_build_location (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
    + + +
    ns3_get() (nepi.resources.ns3.ns3simulation.NS3Simulation method) +
    + + +
    ns3_repo (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
    + + +
    ns3_set() (nepi.resources.ns3.ns3simulation.NS3Simulation method) +
    + + +
    ns3_src_location (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
    + + +
    NS3AarfcdWifiManager (class in nepi.resources.ns3.classes.aarfcd_wifi_manager) +
    + + +
    NS3AarfWifiManager (class in nepi.resources.ns3.classes.aarf_wifi_manager) +
    + + +
    NS3AdhocWifiMac (class in nepi.resources.ns3.classes.adhoc_wifi_mac) +
    + + +
    NS3AlohaNoackNetDevice (class in nepi.resources.ns3.classes.aloha_noack_net_device) +
    + + +
    NS3AmrrWifiManager (class in nepi.resources.ns3.classes.amrr_wifi_manager) +
    + + +
    NS3ApWifiMac (class in nepi.resources.ns3.classes.ap_wifi_mac) +
    + + +
    NS3ArfWifiManager (class in nepi.resources.ns3.classes.arf_wifi_manager) +
    + + +
    NS3ArpL3Protocol (class in nepi.resources.ns3.classes.arp_l3protocol) +
    + + +
    NS3Base (class in nepi.resources.ns3.ns3base) +
    + + +
    NS3BaseApplication (class in nepi.resources.ns3.ns3application) +
    + + +
    NS3BaseArpL3Protocol (class in nepi.resources.ns3.ns3arpl3protocol) +
    + + +
    NS3BaseCCNDceApplication (class in nepi.resources.ns3.ns3ccndceapplication) +
    + + +
    NS3BaseChannel (class in nepi.resources.ns3.ns3channel) +
    + + +
    NS3BaseDceApplication (class in nepi.resources.ns3.ns3dceapplication) +
    + + +
    NS3BaseErrorModel (class in nepi.resources.ns3.ns3errormodel) +
    + + +
    NS3BaseErrorRateModel (class in nepi.resources.ns3.ns3errorratemodel) +
    + + +
    NS3BaseFdNetDevice (class in nepi.resources.ns3.ns3fdnetdevice) +
    + + +
    NS3BaseIcmpv4L4Protocol (class in nepi.resources.ns3.ns3icmpv4l4protocol) +
    + + +
    NS3BaseIpv4L3Protocol (class in nepi.resources.ns3.ns3ipv4l3protocol) +
    + + +
    NS3BaseMobilityModel (class in nepi.resources.ns3.ns3mobilitymodel) +
    + + +
    NS3BaseNetDevice (class in nepi.resources.ns3.ns3netdevice) +
    + + +
    NS3BaseNode (class in nepi.resources.ns3.ns3node) +
    + + +
    NS3BasePipeChannel (class in nepi.resources.ns3.ns3pipechanel) +
    + + +
    NS3BasePropagationDelayModel (class in nepi.resources.ns3.ns3propagationdelaymodel) +
    + + +
    NS3BasePropagationLossModel (class in nepi.resources.ns3.ns3propagationlossmodel) +
    + + +
    NS3BaseQueue (class in nepi.resources.ns3.ns3queue) +
    + + +
    NS3BaseStationNetDevice (class in nepi.resources.ns3.classes.base_station_net_device) +
    + + +
    NS3BaseWifiChannel (class in nepi.resources.ns3.ns3wifichannel) +
    + + +
    NS3BaseWifiMac (class in nepi.resources.ns3.ns3wifimac) +
    + + +
    NS3BaseWifiNetDevice (class in nepi.resources.ns3.ns3wifinetdevice) +
    + + +
    NS3BaseWifiPhy (class in nepi.resources.ns3.ns3wifiphy) +
    + + +
    NS3BaseWifiRemoteStationManager (class in nepi.resources.ns3.ns3wifiremotestationmanager) +
    + + +
    NS3BinaryErrorModel (class in nepi.resources.ns3.classes.binary_error_model) +
    + + +
    NS3BinaryErrorSixlowModel (class in nepi.resources.ns3.classes.binary_error_sixlow_model) +
    + + +
    NS3BridgeChannel (class in nepi.resources.ns3.classes.bridge_channel) +
    + + +
    NS3BridgeNetDevice (class in nepi.resources.ns3.classes.bridge_net_device) +
    + + +
    NS3BulkSendApplication (class in nepi.resources.ns3.classes.bulk_send_application) +
    + + +
    NS3BurstErrorModel (class in nepi.resources.ns3.classes.burst_error_model) +
    + + +
    NS3CaraWifiManager (class in nepi.resources.ns3.classes.cara_wifi_manager) +
    + + +
    NS3Client (class in nepi.resources.ns3.ns3client) +
    + + +
    NS3ConstantAccelerationMobilityModel (class in nepi.resources.ns3.classes.constant_acceleration_mobility_model) +
    + + +
    NS3ConstantPositionMobilityModel (class in nepi.resources.ns3.classes.constant_position_mobility_model) +
    + + +
    NS3ConstantRateWifiManager (class in nepi.resources.ns3.classes.constant_rate_wifi_manager) +
    + + +
    NS3ConstantSpeedPropagationDelayModel (class in nepi.resources.ns3.classes.constant_speed_propagation_delay_model) +
    + + +
    NS3ConstantVelocityMobilityModel (class in nepi.resources.ns3.classes.constant_velocity_mobility_model) +
    + + +
    NS3Cost231PropagationLossModel (class in nepi.resources.ns3.classes.cost231propagation_loss_model) +
    + + +
    NS3CsmaChannel (class in nepi.resources.ns3.classes.csma_channel) +
    + + +
    NS3CsmaNetDevice (class in nepi.resources.ns3.classes.csma_net_device) +
    + + +
    NS3DceHelper (class in nepi.resources.ns3.ns3dcehelper) +
    + + +
    NS3DropTailQueue (class in nepi.resources.ns3.classes.drop_tail_queue) +
    + + +
    NS3dsrDsrRouting (class in nepi.resources.ns3.classes.dsrdsr_routing) +
    + + +
    NS3EmuNetDevice (class in nepi.resources.ns3.classes.emu_net_device) +
    + + +
    NS3ErrorChannel (class in nepi.resources.ns3.classes.error_channel) +
    + + +
    NS3ErrorChannelSixlow (class in nepi.resources.ns3.classes.error_channel_sixlow) +
    + + +
    NS3ErrorNetDevice (class in nepi.resources.ns3.classes.error_net_device) +
    + + +
    NS3FdNetDevice (class in nepi.resources.ns3.classes.fd_net_device) +
    + + +
    NS3FixedRssLossModel (class in nepi.resources.ns3.classes.fixed_rss_loss_model) +
    + + +
    NS3FriisPropagationLossModel (class in nepi.resources.ns3.classes.friis_propagation_loss_model) +
    + + +
    NS3GaussMarkovMobilityModel (class in nepi.resources.ns3.classes.gauss_markov_mobility_model) +
    + + +
    NS3HierarchicalMobilityModel (class in nepi.resources.ns3.classes.hierarchical_mobility_model) +
    + + +
    NS3HybridBuildingsPropagationLossModel (class in nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model) +
    + + +
    NS3Icmpv4L4Protocol (class in nepi.resources.ns3.classes.icmpv4l4protocol) +
    + + +
    NS3Icmpv6L4Protocol (class in nepi.resources.ns3.classes.icmpv6l4protocol) +
    + + +
    NS3IdealWifiManager (class in nepi.resources.ns3.classes.ideal_wifi_manager) +
    + + +
    NS3Ipv4L3Protocol (class in nepi.resources.ns3.classes.ipv4l3protocol) +
    + + +
    NS3ItuR1411LosPropagationLossModel (class in nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model) +
    + + +
    NS3ItuR1411NlosOverRooftopPropagationLossModel (class in nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model) +
    + + +
    NS3JakesPropagationLossModel (class in nepi.resources.ns3.classes.jakes_propagation_loss_model) +
    + + +
    NS3Kun2600MhzPropagationLossModel (class in nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model) +
    + + +
    NS3ListErrorModel (class in nepi.resources.ns3.classes.list_error_model) +
    + + +
    NS3LogDistancePropagationLossModel (class in nepi.resources.ns3.classes.log_distance_propagation_loss_model) +
    + + +
    NS3LoopbackNetDevice (class in nepi.resources.ns3.classes.loopback_net_device) +
    + + +
    NS3LrWpanNetDevice (class in nepi.resources.ns3.classes.lr_wpan_net_device) +
    + + +
    NS3LteEnbNetDevice (class in nepi.resources.ns3.classes.lte_enb_net_device) +
    + + +
    NS3LteSimpleNetDevice (class in nepi.resources.ns3.classes.lte_simple_net_device) +
    + + +
    NS3LteUeNetDevice (class in nepi.resources.ns3.classes.lte_ue_net_device) +
    + + +
    NS3MatrixPropagationLossModel (class in nepi.resources.ns3.classes.matrix_propagation_loss_model) +
    + + +
    NS3MeshPointDevice (class in nepi.resources.ns3.classes.mesh_point_device) +
    + + +
    NS3MeshWifiInterfaceMac (class in nepi.resources.ns3.classes.mesh_wifi_interface_mac) +
    + + +
    NS3MinstrelWifiManager (class in nepi.resources.ns3.classes.minstrel_wifi_manager) +
    + + +
    NS3MultiModelSpectrumChannel (class in nepi.resources.ns3.classes.multi_model_spectrum_channel) +
    + + +
    NS3NakagamiPropagationLossModel (class in nepi.resources.ns3.classes.nakagami_propagation_loss_model) +
    + + +
    NS3NistErrorRateModel (class in nepi.resources.ns3.classes.nist_error_rate_model) +
    + + +
    NS3Node (class in nepi.resources.ns3.classes.node) +
    + + +
    NS3NonCommunicatingNetDevice (class in nepi.resources.ns3.classes.non_communicating_net_device) +
    + + +
    NS3OcbWifiMac (class in nepi.resources.ns3.classes.ocb_wifi_mac) +
    + + +
    NS3OhBuildingsPropagationLossModel (class in nepi.resources.ns3.classes.oh_buildings_propagation_loss_model) +
    + + +
    NS3OkumuraHataPropagationLossModel (class in nepi.resources.ns3.classes.okumura_hata_propagation_loss_model) +
    + + +
    NS3OnoeWifiManager (class in nepi.resources.ns3.classes.onoe_wifi_manager) +
    + + +
    NS3OnOffApplication (class in nepi.resources.ns3.classes.on_off_application) +
    + + +
    NS3PacketSink (class in nepi.resources.ns3.classes.packet_sink) +
    + + +
    NS3Ping6 (class in nepi.resources.ns3.classes.ping6) +
    + + +
    NS3PointToPointChannel (class in nepi.resources.ns3.classes.point_to_point_channel) +
    + + +
    NS3PointToPointNetDevice (class in nepi.resources.ns3.classes.point_to_point_net_device) +
    + + +
    NS3PointToPointRemoteChannel (class in nepi.resources.ns3.classes.point_to_point_remote_channel) +
    + + +
    NS3Radvd (class in nepi.resources.ns3.classes.radvd) +
    + + +
    NS3RandomDirection2dMobilityModel (class in nepi.resources.ns3.classes.random_direction2d_mobility_model) +
    + + +
    NS3RandomPropagationDelayModel (class in nepi.resources.ns3.classes.random_propagation_delay_model) +
    + + +
    NS3RandomPropagationLossModel (class in nepi.resources.ns3.classes.random_propagation_loss_model) +
    + + +
    NS3RandomWalk2dMobilityModel (class in nepi.resources.ns3.classes.random_walk2d_mobility_model) +
    + + +
    NS3RandomWaypointMobilityModel (class in nepi.resources.ns3.classes.random_waypoint_mobility_model) +
    + + +
    NS3RangePropagationLossModel (class in nepi.resources.ns3.classes.range_propagation_loss_model) +
    + + +
    NS3RateErrorModel (class in nepi.resources.ns3.classes.rate_error_model) +
    + + +
    NS3ReceiveListErrorModel (class in nepi.resources.ns3.classes.receive_list_error_model) +
    + + +
    NS3RedQueue (class in nepi.resources.ns3.classes.red_queue) +
    + + +
    NS3Route (class in nepi.resources.ns3.ns3route) +
    + + +
    NS3RraaWifiManager (class in nepi.resources.ns3.classes.rraa_wifi_manager) +
    + + +
    NS3SimpleChannel (class in nepi.resources.ns3.classes.simple_channel) +
    + + +
    NS3SimpleNetDevice (class in nepi.resources.ns3.classes.simple_net_device) +
    + + +
    NS3Simulation (class in nepi.resources.ns3.ns3simulation) +
    + + +
    NS3SingleModelSpectrumChannel (class in nepi.resources.ns3.classes.single_model_spectrum_channel) +
    + + +
    NS3SixLowPanNetDevice (class in nepi.resources.ns3.classes.six_low_pan_net_device) +
    + + +
    NS3StaWifiMac (class in nepi.resources.ns3.classes.sta_wifi_mac) +
    + + +
    NS3SteadyStateRandomWaypointMobilityModel (class in nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model) +
    + + +
    NS3SubscriberStationNetDevice (class in nepi.resources.ns3.classes.subscriber_station_net_device) +
    + + +
    NS3TapBridge (class in nepi.resources.ns3.classes.tap_bridge) +
    + + +
    NS3TcpL4Protocol (class in nepi.resources.ns3.classes.tcp_l4protocol) +
    + + +
    NS3ThreeLogDistancePropagationLossModel (class in nepi.resources.ns3.classes.three_log_distance_propagation_loss_model) +
    + + +
    NS3TwoRayGroundPropagationLossModel (class in nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model) +
    + + +
    NS3UanChannel (class in nepi.resources.ns3.classes.uan_channel) +
    + + +
    NS3UdpClient (class in nepi.resources.ns3.classes.udp_client) +
    + + +
    NS3UdpEchoClient (class in nepi.resources.ns3.classes.udp_echo_client) +
    + + +
    NS3UdpEchoServer (class in nepi.resources.ns3.classes.udp_echo_server) +
    + + +
    NS3UdpL4Protocol (class in nepi.resources.ns3.classes.udp_l4protocol) +
    + + +
    NS3UdpServer (class in nepi.resources.ns3.classes.udp_server) +
    + + +
    NS3UdpTraceClient (class in nepi.resources.ns3.classes.udp_trace_client) +
    + + +
    NS3V4Ping (class in nepi.resources.ns3.classes.v4ping) +
    + + +
    NS3VirtualNetDevice (class in nepi.resources.ns3.classes.virtual_net_device) +
    + + +
    NS3WaypointMobilityModel (class in nepi.resources.ns3.classes.waypoint_mobility_model) +
    + + +
    NS3WifiNetDevice (class in nepi.resources.ns3.classes.wifi_net_device) +
    + + +
    NS3Wrapper (class in nepi.resources.ns3.ns3wrapper) +
    + + +
    NS3WrapperDebuger (class in nepi.resources.ns3.ns3wrapper_debug) +
    + + +
    NS3WrapperMessage (class in nepi.resources.ns3.ns3server) +
    + + +
    NS3YansErrorRateModel (class in nepi.resources.ns3.classes.yans_error_rate_model) +
    + + +
    NS3YansWifiChannel (class in nepi.resources.ns3.classes.yans_wifi_channel) +
    + + +
    NS3YansWifiPhy (class in nepi.resources.ns3.classes.yans_wifi_phy) +
    + + +
    nthreads (nepi.execution.ec.ExperimentController attribute) +
    + +
    + +

    O

    + + + +
    + +
    OK (nepi.execution.ec.FailureLevel attribute) +
    + +
    + +
    (nepi.resources.linux.node.ExitCode attribute) +
    + +
    + +
    OMF5API (class in nepi.resources.omf.omf5_api) +
    + + +
    OMF6API (class in nepi.resources.omf.omf6_api) +
    + + +
    OMF6Parser (class in nepi.resources.omf.omf6_parser) +
    + + +
    OMFAPIFactory (class in nepi.resources.omf.omf_api_factory) +
    + + +
    OMFApplication (class in nepi.resources.omf.application) +
    + + +
    OMFChannel (class in nepi.resources.omf.channel) +
    + + +
    OMFClient (class in nepi.resources.omf.omf_client) +
    + + +
    OMFNode (class in nepi.resources.omf.node) +
    + +
    + +
    OMFResource (class in nepi.resources.omf.omf_resource) +
    + + +
    OMFWifiInterface (class in nepi.resources.omf.interface) +
    + + +
    open_socket() (in module nepi.resources.ns3.ns3server) +
    + + +
    openssh_has_persist() (in module nepi.util.sshfuncs) +
    + + +
    order (nepi.util.netgraph.NetGraph attribute) +
    + + +
    os (nepi.resources.linux.node.LinuxNode attribute) +
    + + +
    OSType (class in nepi.resources.linux.node) +
    + + +
    ovs_status() (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
    + + +
    ovsswitch (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort attribute) +
    + +
    + +

    P

    + + + +
    + +
    ParallelRun (class in nepi.util.parallel) +
    + + +
    parse_file() (in module nepi.data.processing.ccn.parser) +
    + +
    + +
    (in module nepi.data.processing.ping.parser) +
    + +
    + +
    parse_sfa_rspec() (nepi.util.sfarspec_proc.SfaRSpecProcessing method) +
    + + +
    PATH (nepi.execution.trace.TraceAttr attribute) +
    + + +
    path (nepi.resources.linux.ccn.ccnd.LinuxCCND attribute) +
    + + +
    peer_map (nepi.resources.planetlab.plcapi.PLCAPI attribute) +
    + + +
    pending (nepi.execution.scheduler.HeapScheduler attribute) +
    + + +
    persist (nepi.execution.ec.ExperimentController attribute) +
    + + +
    PFormats (class in nepi.util.plotter) +
    + + +
    phy (nepi.resources.ns3.ns3errorratemodel.NS3BaseErrorRateModel attribute) +
    + + +
    phys (nepi.resources.ns3.ns3wifichannel.NS3BaseWifiChannel attribute) +
    + + +
    pi (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel attribute) +
    + + +
    pid (nepi.resources.linux.application.LinuxApplication attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication attribute) +
    + +
    + +
    ping (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry attribute) +
    + + +
    PlanetlabNode (class in nepi.resources.planetlab.node) +
    + + +
    PlanetlabNs3FdUdpTunnel (class in nepi.resources.planetlab.ns3.fdudptunnel) +
    + + +
    PlanetlabOVSPort (class in nepi.resources.planetlab.openvswitch.ovsport) +
    + + +
    PlanetlabOVSSwitch (class in nepi.resources.planetlab.openvswitch.ovs) +
    + + +
    PlanetlabSfaNode (class in nepi.resources.planetlab.sfa_node) +
    + + +
    PlanetlabTap (class in nepi.resources.planetlab.tap) +
    + + +
    PlanetlabTun (class in nepi.resources.planetlab.tun) +
    + + +
    PlanetlabTunTapFdLink (class in nepi.resources.planetlab.ns3.tuntapfdlink) +
    + + +
    PlanetlabVroute (class in nepi.resources.planetlab.vroute) +
    + + +
    plapi (nepi.resources.planetlab.node.PlanetlabNode attribute) +
    + +
    + +
    PLCAPI (class in nepi.resources.planetlab.plcapi) +
    + + +
    PLCAPIFactory (class in nepi.resources.planetlab.plcapi) +
    + + +
    plot() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.util.plotter.ECPlotter method) +
    + +
    + +
    populate_factory() (in module nepi.execution.resource) +
    + + +
    port_number (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort attribute) +
    + + +
    ppid (nepi.resources.linux.application.LinuxApplication attribute) +
    + + +
    process_content_history() (in module nepi.data.processing.ccn.parser) +
    + + +
    process_content_history_logs() (in module nepi.data.processing.ccn.parser) +
    + + +
    ProcStatus (class in nepi.util.sshfuncs) +
    + + +
    provision() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    provision_time (nepi.execution.resource.ResourceManager attribute) +
    + + +
    PROVISIONED (nepi.execution.resource.ResourceState attribute) +
    + + +
    publish() (nepi.resources.omf.omf_client.OMFClient method) +
    + + +
    purge() (nepi.resources.omf.omf_client.OMFClient method) +
    + + +
    put() (nepi.util.parallel.ParallelRun method) +
    + + +
    put_nowait() (nepi.util.parallel.ParallelRun method) +
    + + +
    pygccxml_version (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
    + + +
    python_passfd_repo (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
    + + +
    python_passfd_src (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
    + + +
    python_passfd_version (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
    + + +
    python_unshare_repo (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
    + + +
    python_unshare_src (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
    + + +
    python_unshare_version (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
    + +
    + +

    Q

    + + + +
    + +
    queue (nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice attribute) +
    + +
    + +
    quit() (nepi.util.parallel.WorkerThread method) +
    + +
    + +

    R

    + + + +
    + +
    range (nepi.execution.attribute.Attribute attribute) +
    + + +
    rcopy() (in module nepi.util.sshfuncs) +
    + + +
    READY (nepi.execution.resource.ResourceState attribute) +
    + + +
    ready (nepi.resources.omf.omf_client.OMFClient attribute) +
    + + +
    ready_time (nepi.execution.resource.ResourceManager attribute) +
    + + +
    recv_fd() (nepi.resources.ns3.ns3fdnetdevice.NS3BaseFdNetDevice method) +
    + + +
    recv_msg() (in module nepi.resources.netns.netnsserver) +
    + +
    + +
    (in module nepi.resources.ns3.ns3server) +
    + +
    + +
    register() (nepi.resources.omf.omf_client.OMFClient method) +
    + + +
    register_condition() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    register_connection() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    register_resource() (nepi.execution.ec.ExperimentController method) +
    + + +
    register_type() (nepi.execution.resource.ResourceFactory class method) +
    + + +
    release() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + + +
    (nepi.resources.omf.omf5_api.OMF5API method) +
    + + +
    (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    (nepi.util.sfaapi.SFAAPI method) +
    + +
    + +
    release_api() (nepi.resources.omf.omf_api_factory.OMFAPIFactory class method) +
    + + +
    release_function() (nepi.resources.omf.messages_6.MessageHandler method) +
    + + +
    release_time (nepi.execution.resource.ResourceManager attribute) +
    + + +
    RELEASED (nepi.execution.ec.ECState attribute) +
    + +
    + +
    (nepi.execution.resource.ResourceState attribute) +
    + +
    + +
    remote_socket (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
    + +
    + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
    + +
    + +
    remove() (nepi.execution.scheduler.HeapScheduler method) +
    + + +
    remove_all_from_slice() (nepi.util.sfaapi.SFAAPI method) +
    + + +
    remove_packages() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    remove_packages_command() (in module nepi.resources.linux.debfuncs) +
    + +
    + +
    (in module nepi.resources.linux.rpmfuncs) +
    + +
    + +
    remove_resource() (nepi.execution.ec.ExperimentController method) +
    + + +
    remove_resource_from_slice() (nepi.util.manifoldapi.MANIFOLDAPI method) +
    + +
    + +
    (nepi.util.sfaapi.SFAAPI method) +
    + +
    + +
    replace_args() (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
    + +
    + +
    replace_kwargs() (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
    + +
    + +
    replace_paths() (nepi.resources.linux.application.LinuxApplication method) +
    + +
    + +
    (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
    + + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
    + +
    + +
    request_function() (nepi.resources.omf.messages_6.MessageHandler method) +
    + + +
    reschedule_delay (nepi.execution.resource.ResourceManager attribute) +
    + + +
    reserve() (nepi.execution.resource.ResourceManager method) +
    + + +
    reserve_host() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + +
    + +
    reserve_resource() (nepi.util.sfaapi.SFAAPI method) +
    + + +
    Reserved (nepi.execution.attribute.Flags attribute) +
    + + +
    RESERVED (nepi.execution.resource.ResourceState attribute) +
    + + +
    reserved() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + +
    + +
    (nepi.util.sfaapi.SFAAPI method) +
    + +
    + +
    reserved_time (nepi.execution.resource.ResourceManager attribute) +
    + + +
    resolve_hostname() (in module nepi.util.sshfuncs) +
    + + +
    resource_types() (nepi.execution.resource.ResourceFactory class method) +
    + + +
    ResourceAction (class in nepi.execution.resource) +
    + + +
    ResourceFactory (class in nepi.execution.resource) +
    + + +
    ResourceGateway (class in nepi.resources.omf.omf_resource) +
    + + +
    ResourceManager (class in nepi.execution.resource) +
    + + +
    resources (nepi.execution.ec.ExperimentController attribute) +
    + + +
    ResourceState (class in nepi.execution.resource) +
    + + +
    retract() (nepi.resources.omf.omf_client.OMFClient method) +
    + + +
    rexec() (in module nepi.util.sshfuncs) +
    + + +
    rgetpid() (in module nepi.util.sshfuncs) +
    + + +
    rkill() (in module nepi.util.sshfuncs) +
    + + +
    RM_FAILURE (nepi.execution.ec.FailureLevel attribute) +
    + + +
    rmdir() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    rspawn() (in module nepi.util.sshfuncs) +
    + + +
    rstatus() (in module nepi.util.sshfuncs) +
    + + +
    run() (nepi.execution.runner.ExperimentRunner method) +
    + +
    + +
    (nepi.resources.linux.node.LinuxNode method) +
    + + +
    (nepi.util.parallel.WorkerThread method) +
    + +
    + +
    run_and_wait() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    run_dir (nepi.execution.ec.ExperimentController attribute) +
    + + +
    run_experiment() (nepi.execution.runner.ExperimentRunner method) +
    + + +
    run_home (nepi.resources.linux.application.LinuxApplication attribute) +
    + +
    + +
    (nepi.resources.linux.node.LinuxNode attribute) +
    + +
    + +
    run_home() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + +
    + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + +
    + +
    run_id (nepi.execution.ec.ExperimentController attribute) +
    + + +
    run_server() (in module nepi.resources.netns.netnsserver) +
    + +
    + +
    (in module nepi.resources.ns3.ns3server) +
    + +
    + +
    RUNNING (nepi.execution.ec.ECState attribute) +
    + +
    + +
    (nepi.util.sshfuncs.ProcStatus attribute) +
    + +
    +
    + +

    S

    + + + +
    + +
    save() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.util.serializer.ECSerializer method) +
    + +
    + +
    schedule() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.scheduler.HeapScheduler method) +
    + +
    + +
    script_path (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger attribute) +
    + +
    + +
    select_base_class() (in module nepi.resources.ns3.resource_manager_generator) +
    + + +
    select_random_source() (nepi.util.netgraph.NetGraph method) +
    + + +
    select_target_zero() (nepi.util.netgraph.NetGraph method) +
    + + +
    send_msg() (nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
    + +
    + +
    (nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
    + +
    + +
    send_reply() (in module nepi.resources.netns.netnsserver) +
    + +
    + +
    (in module nepi.resources.ns3.ns3server) +
    + +
    + +
    send_stdin() (nepi.resources.omf.omf5_api.OMF5API method) +
    + + +
    serialize() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.util.serializer.ECSerializer method) +
    + +
    + +
    servers_on() (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
    + + +
    SET (nepi.resources.netns.netnsserver.NetNSWrapperMessage attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
    + +
    + +
    set() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + + +
    (nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
    + + +
    (nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
    + + +
    (nepi.resources.netns.netnsbase.NetNSBase method) +
    + + +
    (nepi.resources.netns.netnsclient.NetNSClient method) +
    + + +
    (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
    + + +
    (nepi.resources.ns3.ns3base.NS3Base method) +
    + + +
    (nepi.resources.ns3.ns3client.NS3Client method) +
    + + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
    + +
    + +
    set_discovered() (nepi.execution.resource.ResourceManager method) +
    + + +
    set_ec() (nepi.execution.ec.FailureManager method) +
    + + +
    set_ec_failure() (nepi.execution.ec.FailureManager method) +
    + + +
    set_failed() (nepi.execution.resource.ResourceManager method) +
    + + +
    set_global() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager class method) +
    + +
    + +
    set_hook_mtu() (nepi.resources.linux.interface.LinuxInterface method) +
    + + +
    set_hook_up() (nepi.resources.linux.interface.LinuxInterface method) +
    + + +
    set_provisioned() (nepi.execution.resource.ResourceManager method) +
    + + +
    set_ready() (nepi.execution.resource.ResourceManager method) +
    + + +
    set_released() (nepi.execution.resource.ResourceManager method) +
    + + +
    set_reserved() (nepi.execution.resource.ResourceManager method) +
    + + +
    set_source() (nepi.util.netgraph.NetGraph method) +
    + + +
    set_started() (nepi.execution.resource.ResourceManager method) +
    + + +
    set_state() (nepi.execution.resource.ResourceManager method) +
    + + +
    set_state_time() (nepi.execution.resource.ResourceManager method) +
    + + +
    set_stopped() (nepi.execution.resource.ResourceManager method) +
    + + +
    set_target() (nepi.util.netgraph.NetGraph method) +
    + + +
    set_value() (nepi.execution.attribute.Attribute method) +
    + + +
    set_with_conditions() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    SFAAPI (class in nepi.util.sfaapi) +
    + + +
    sfaapi (nepi.resources.omf.wilabt_node.WilabtSfaNode attribute) +
    + +
    + +
    (nepi.resources.planetlab.sfa_node.PlanetlabSfaNode attribute) +
    + +
    + +
    SFAAPIFactory (class in nepi.util.sfaapi) +
    + + +
    SfaRSpecProcessing (class in nepi.util.sfarspec_proc) +
    + + +
    SFormats (class in nepi.util.serializer) +
    + +
    + +
    share_dir (nepi.resources.linux.node.LinuxNode attribute) +
    + + +
    shell_escape() (in module nepi.util.sshfuncs) +
    + + +
    SHUTDOWN (nepi.resources.netns.netnsserver.NetNSWrapperMessage attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
    + +
    + +
    shutdown() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
    + + +
    (nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
    + + +
    (nepi.resources.netns.netnsclient.NetNSClient method) +
    + + +
    (nepi.resources.netns.netnsemulation.NetNSEmulation method) +
    + + +
    (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
    + + +
    (nepi.resources.ns3.ns3client.NS3Client method) +
    + + +
    (nepi.resources.ns3.ns3simulation.NS3Simulation method) +
    + + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
    + +
    + +
    simulation (nepi.resources.linux.ns3.ns3client.LinuxNS3Client attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3base.NS3Base attribute) +
    + + +
    (nepi.resources.ns3.ns3channel.NS3BaseChannel attribute) +
    + + +
    (nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
    + + +
    (nepi.resources.ns3.ns3propagationdelaymodel.NS3BasePropagationDelayModel attribute) +
    + + +
    (nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel attribute) +
    + + +
    (nepi.resources.ns3.ns3wifichannel.NS3BaseWifiChannel attribute) +
    + +
    + +
    SIZE (nepi.execution.trace.TraceAttr attribute) +
    + + +
    sock_name (nepi.resources.linux.tap.LinuxTap attribute) +
    + + +
    socket_name (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
    + +
    + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
    + +
    + +
    sources() (nepi.util.netgraph.NetGraph method) +
    + + +
    src_dir (nepi.resources.linux.node.LinuxNode attribute) +
    + + +
    stabsformat() (in module nepi.util.timefuncs) +
    + + +
    STAR (nepi.util.netgraph.TopologyType attribute) +
    + + +
    START (nepi.execution.resource.ResourceAction attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
    + +
    + +
    start() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + + +
    (nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
    + + +
    (nepi.resources.ns3.ns3client.NS3Client method) +
    + + +
    (nepi.resources.ns3.ns3simulation.NS3Simulation method) +
    + + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
    + + +
    (nepi.resources.omf.omf_client.OMFClient method) +
    + + +
    (nepi.util.parallel.ParallelRun method) +
    + +
    + +
    start_multicall() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    start_time (nepi.execution.resource.ResourceManager attribute) +
    + + +
    start_with_conditions() (nepi.execution.resource.ResourceManager method) +
    + + +
    STARTED (nepi.execution.resource.ResourceState attribute) +
    + + +
    state (nepi.execution.resource.ResourceManager attribute) +
    + +
    + +
    (nepi.resources.linux.application.LinuxApplication attribute) +
    + + +
    (nepi.resources.linux.ccn.ccnd.LinuxCCND attribute) +
    + + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
    + + +
    (nepi.resources.linux.tap.LinuxTap attribute) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel attribute) +
    + + +
    (nepi.resources.netns.netnsapplication.NetNSApplication attribute) +
    + + +
    (nepi.resources.netns.netnsbase.NetNSBase attribute) +
    + + +
    (nepi.resources.ns3.ns3application.NS3BaseApplication attribute) +
    + + +
    (nepi.resources.ns3.ns3base.NS3Base attribute) +
    + +
    + +
    state() (nepi.execution.ec.ExperimentController method) +
    + + +
    status() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    stdin_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
    + + +
    stdin_hook() (nepi.resources.omf.application.OMFApplication method) +
    + + +
    STDOUT (class in nepi.util.sshfuncs) +
    + + +
    stformat() (in module nepi.util.timefuncs) +
    + + +
    STOP (nepi.execution.resource.ResourceAction attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
    + +
    + +
    stop() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + + +
    (nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
    + + +
    (nepi.resources.ns3.ns3client.NS3Client method) +
    + + +
    (nepi.resources.ns3.ns3simulation.NS3Simulation method) +
    + + +
    (nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
    + +
    + +
    stop_time (nepi.execution.resource.ResourceManager attribute) +
    + + +
    stop_with_conditions() (nepi.execution.resource.ResourceManager method) +
    + + +
    STOPPED (nepi.execution.resource.ResourceState attribute) +
    + + +
    store_path (nepi.resources.all.collector.Collector attribute) +
    + + +
    STREAM (nepi.execution.trace.TraceAttr attribute) +
    + + +
    String (nepi.execution.attribute.Types attribute) +
    + + +
    subscribe() (nepi.resources.omf.omf_client.OMFClient method) +
    + + +
    subscriptions() (nepi.resources.omf.omf_client.OMFClient method) +
    + + +
    switch (nepi.resources.netns.netnsnodeinterface.NetNSNodeInterface attribute) +
    + + +
    sync() (nepi.util.parallel.ParallelRun method) +
    + +
    + +

    T

    + + + +
    + +
    tap (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink attribute) +
    + +
    + +
    (nepi.resources.planetlab.ns3.tuntapfdlink.PlanetlabTunTapFdLink attribute) +
    + + +
    (nepi.resources.planetlab.vroute.PlanetlabVroute attribute) +
    + +
    + +
    tapnode (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink attribute) +
    + + +
    targets() (nepi.util.netgraph.NetGraph method) +
    + + +
    Task (class in nepi.execution.scheduler) +
    + + +
    TaskStatus (class in nepi.execution.scheduler) +
    + + +
    tdiff() (in module nepi.util.timefuncs) +
    + + +
    tdiffsec() (in module nepi.util.timefuncs) +
    + + +
    template_attributes() (in module nepi.resources.ns3.resource_manager_generator) +
    + + +
    template_traces() (in module nepi.resources.ns3.resource_manager_generator) +
    + + +
    terminate_connection() (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
    + +
    + +
    (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    (nepi.resources.linux.tap.LinuxTap method) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + + +
    (nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
    + + +
    (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
    + +
    + +
    TERMINATED (nepi.execution.ec.ECState attribute) +
    + + +
    test() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    TestbedtoGateway (nepi.resources.omf.omf_resource.ResourceGateway attribute) +
    + + +
    tnow() (in module nepi.util.timefuncs) +
    + + +
    to_type() (in module nepi.util.parsers.xml_parser) +
    + +
    + +
    to_xml() (nepi.util.parsers.xml_parser.ECXMLParser method) +
    + + +
    topo_type (nepi.util.netgraph.NetGraph attribute) +
    + + +
    topology (nepi.util.netgraph.NetGraph attribute) +
    + + +
    TopologyType (class in nepi.util.netgraph) +
    + + +
    Trace (class in nepi.execution.trace) +
    + + +
    trace() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + + +
    (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
    + + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
    + + +
    (nepi.resources.netns.netnsbase.NetNSBase method) +
    + + +
    (nepi.resources.ns3.ns3base.NS3Base method) +
    + + +
    (nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication method) +
    + + +
    (nepi.resources.omf.application.OMFApplication method) +
    + +
    + +
    trace_enabled() (nepi.execution.ec.ExperimentController method) +
    + +
    + +
    (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    trace_filepath() (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    TraceAttr (class in nepi.execution.trace) +
    + + +
    traceroute (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry attribute) +
    + + +
    TREE (nepi.util.netgraph.TopologyType attribute) +
    + + +
    tsformat() (in module nepi.util.timefuncs) +
    + + +
    type (nepi.execution.attribute.Attribute attribute) +
    + + +
    Types (class in nepi.execution.attribute) +
    + +
    + +

    U

    + + + +
    + +
    UBUNTU (nepi.resources.linux.node.OSType attribute) +
    + + +
    udp_connect() (nepi.resources.linux.tap.LinuxTap method) +
    + + +
    unblacklist_host() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    unenroll_topic() (nepi.resources.omf.omf6_api.OMF6API method) +
    + + +
    unregister() (nepi.resources.omf.omf_client.OMFClient method) +
    + + +
    unregister_condition() (nepi.execution.resource.ResourceManager method) +
    + + +
    unregister_connection() (nepi.execution.resource.ResourceManager method) +
    + + +
    unreserve_host() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    unsubscribe() (nepi.resources.omf.omf_client.OMFClient method) +
    + + +
    update_slice() (nepi.resources.planetlab.plcapi.PLCAPI method) +
    + + +
    upload() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    upload_binaries() (nepi.resources.linux.application.LinuxApplication method) +
    + +
    + +
    upload_code() (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    upload_command() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    upload_extra_sources() (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
    + +
    + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
    + +
    + +
    upload_files() (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    upload_libraries() (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    upload_sources() (nepi.resources.linux.application.LinuxApplication method) +
    + +
    + +
    (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
    + + +
    (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
    + + +
    (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink method) +
    + + +
    (nepi.resources.linux.route.LinuxRoute method) +
    + + +
    (nepi.resources.linux.tap.LinuxTap method) +
    + + +
    (nepi.resources.planetlab.ns3.tuntapfdlink.PlanetlabTunTapFdLink method) +
    + + +
    (nepi.resources.planetlab.tap.PlanetlabTap method) +
    + + +
    (nepi.resources.planetlab.vroute.PlanetlabVroute method) +
    + +
    + +
    upload_start_command() (nepi.resources.linux.application.LinuxApplication method) +
    + +
    + +
    (nepi.resources.linux.ccn.ccncontent.LinuxCCNContent method) +
    + + +
    (nepi.resources.linux.ccn.ccnd.LinuxCCND method) +
    + + +
    (nepi.resources.linux.ccn.ccnr.LinuxCCNR method) +
    + + +
    (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
    + + +
    (nepi.resources.linux.mtr.LinuxMtr method) +
    + + +
    (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
    + + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
    + + +
    (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink method) +
    + + +
    (nepi.resources.linux.ping.LinuxPing method) +
    + + +
    (nepi.resources.linux.route.LinuxRoute method) +
    + + +
    (nepi.resources.linux.tap.LinuxTap method) +
    + + +
    (nepi.resources.linux.traceroute.LinuxTraceroute method) +
    + + +
    (nepi.resources.linux.udptest.LinuxUdpTest method) +
    + + +
    (nepi.resources.planetlab.tap.PlanetlabTap method) +
    + + +
    (nepi.resources.planetlab.vroute.PlanetlabVroute method) +
    + +
    + +
    upload_stdin() (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    use_deb (nepi.resources.linux.node.LinuxNode attribute) +
    + + +
    use_rpm (nepi.resources.linux.node.LinuxNode attribute) +
    + + +
    usr_dir (nepi.resources.linux.node.LinuxNode attribute) +
    + + +
    uuid (nepi.resources.netns.netnsbase.NetNSBase attribute) +
    + +
    + +
    (nepi.resources.ns3.ns3base.NS3Base attribute) +
    + +
    +
    + +

    V

    + + + +
    + +
    valid_connection() (nepi.execution.resource.ResourceManager method) +
    + +
    + +
    (nepi.resources.all.collector.Collector method) +
    + + +
    (nepi.resources.linux.application.LinuxApplication method) +
    + + +
    (nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication method) +
    + + +
    (nepi.resources.linux.ccn.ccncat.LinuxCCNCat method) +
    + + +
    (nepi.resources.linux.ccn.ccncontent.LinuxCCNContent method) +
    + + +
    (nepi.resources.linux.ccn.ccnd.LinuxCCND method) +
    + + +
    (nepi.resources.linux.ccn.ccnpeek.LinuxCCNPeek method) +
    + + +
    (nepi.resources.linux.ccn.ccnping.LinuxCCNPing method) +
    + + +
    (nepi.resources.linux.ccn.ccnpingserver.LinuxCCNPingServer method) +
    + + +
    (nepi.resources.linux.ccn.ccnpoke.LinuxCCNPoke method) +
    + + +
    (nepi.resources.linux.ccn.ccnr.LinuxCCNR method) +
    + + +
    (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
    + + +
    (nepi.resources.linux.channel.LinuxChannel method) +
    + + +
    (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
    + + +
    (nepi.resources.linux.interface.LinuxInterface method) +
    + + +
    (nepi.resources.linux.mtr.LinuxMtr method) +
    + + +
    (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
    + + +
    (nepi.resources.linux.node.LinuxNode method) +
    + + +
    (nepi.resources.linux.nping.LinuxNPing method) +
    + + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
    + + +
    (nepi.resources.linux.ping.LinuxPing method) +
    + + +
    (nepi.resources.linux.tap.LinuxTap method) +
    + + +
    (nepi.resources.linux.tcpdump.LinuxTcpdump method) +
    + + +
    (nepi.resources.linux.traceroute.LinuxTraceroute method) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + + +
    (nepi.resources.linux.udptest.LinuxUdpTest method) +
    + + +
    (nepi.resources.omf.application.OMFApplication method) +
    + + +
    (nepi.resources.omf.channel.OMFChannel method) +
    + + +
    (nepi.resources.omf.interface.OMFWifiInterface method) +
    + + +
    (nepi.resources.omf.node.OMFNode method) +
    + + +
    (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
    + + +
    (nepi.resources.planetlab.node.PlanetlabNode method) +
    + + +
    (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
    + + +
    (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
    + + +
    (nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
    + + +
    (nepi.resources.planetlab.tap.PlanetlabTap method) +
    + + +
    (nepi.resources.planetlab.vroute.PlanetlabVroute method) +
    + +
    + +
    value (nepi.execution.attribute.Attribute attribute) +
    + + +
    verify() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    verify_connection() (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
    + +
    + +
    (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    (nepi.resources.linux.tap.LinuxTap method) +
    + + +
    (nepi.resources.linux.tunnel.LinuxTunnel method) +
    + + +
    (nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
    + + +
    (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
    + +
    + +
    version (nepi.resources.linux.ccn.ccnd.LinuxCCND attribute) +
    + +
    + +
    (nepi.resources.linux.ns3.ccn.ns3ccnddceapplication.LinuxNS3DceCCND attribute) +
    + +
    +
    + +
    vif_name_file (nepi.resources.planetlab.tap.PlanetlabTap attribute) +
    + + +
    vif_prefix (nepi.resources.linux.tap.LinuxTap attribute) +
    + + +
    vif_type (nepi.resources.linux.tap.LinuxTap attribute) +
    + + +
    vif_type_flag (nepi.resources.linux.tap.LinuxTap attribute) +
    + +
    + +

    W

    + + + +
    + +
    wait() (nepi.execution.ec.ExperimentController method) +
    + + +
    wait_deployed() (nepi.execution.ec.ExperimentController method) +
    + + +
    wait_file() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + +
    + +
    (nepi.resources.linux.tap.LinuxTap method) +
    + +
    + +
    wait_finished() (nepi.execution.ec.ExperimentController method) +
    + + +
    wait_local_port() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    wait_pid() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    wait_released() (nepi.execution.ec.ExperimentController method) +
    + + +
    wait_remote_socket() (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
    + +
    + +
    (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
    + +
    +
    + +
    wait_result() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
    + + +
    wait_run() (nepi.resources.linux.node.LinuxNode method) +
    + + +
    wait_started() (nepi.execution.ec.ExperimentController method) +
    + + +
    wait_vif_name() (nepi.resources.planetlab.tap.PlanetlabTap method) +
    + + +
    warning() (nepi.util.logger.Logger method) +
    + + +
    WilabtSfaNode (class in nepi.resources.omf.wilabt_node) +
    + + +
    WorkerThread (class in nepi.util.parallel) +
    + + +
    WorkerThread.QUIT (class in nepi.util.parallel) +
    + +
    + +

    X

    + + + +
    + +
    XML (nepi.util.serializer.SFormats attribute) +
    + + +
    xmldecode() (in module nepi.util.parsers.xml_parser) +
    + +
    + +
    xmlencode() (in module nepi.util.parsers.xml_parser) +
    + +
    + + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/index.html b/doc/sphinx/_build/html/index.html new file mode 100644 index 00000000..f5861b3c --- /dev/null +++ b/doc/sphinx/_build/html/index.html @@ -0,0 +1,201 @@ + + + + + + + + NEPI modules — NEPI 3.0 documentation + + + + + + + + + + + + +
    +
    +

    Table Of Contents

    + + +

    This Page

    + + + +
    +
    + +
    +
    +
    +
    + +
    +

    NEPI modules¶

    +

    This page documents the NEPI source code. It presents the NEPI core modules, the Platform resource modules (i.e. drivers to manage platforms), and other miscellaneous classes.

    +
    +

    Core modules¶

    +
    +
    +
    +
    +
    +

    Platform modules¶

    +
    +
    +
    +
    +
    +

    Miscellaneous modules¶

    +
    +
    +
    +
    +
      +
    +
    +
    +
    +
    +

    Indices and tables¶

    + +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/objects.inv b/doc/sphinx/_build/html/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..2c3613a6160d0fae8c9c7b854f44032b594d045c GIT binary patch literal 16497 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�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 + + + + + + + Python Module Index — NEPI 3.0 documentation + + + + + + + + + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +
    + + +

    Python Module Index

    + +
    + n +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    + n
    + nepi +
        + nepi.data +
        + nepi.data.processing +
        + nepi.data.processing.ccn +
        + nepi.data.processing.ccn.parser +
        + nepi.data.processing.ping +
        + nepi.data.processing.ping.parser +
        + nepi.execution +
        + nepi.execution.attribute +
        + nepi.execution.ec +
        + nepi.execution.resource +
        + nepi.execution.runner +
        + nepi.execution.scheduler +
        + nepi.execution.tags +
        + nepi.execution.trace +
        + nepi.resources +
        + nepi.resources.all +
        + nepi.resources.all.collector +
        + nepi.resources.linux +
        + nepi.resources.linux.application +
        + nepi.resources.linux.ccn +
        + nepi.resources.linux.ccn.ccnapplication +
        + nepi.resources.linux.ccn.ccncat +
        + nepi.resources.linux.ccn.ccncontent +
        + nepi.resources.linux.ccn.ccnd +
        + nepi.resources.linux.ccn.ccnpeek +
        + nepi.resources.linux.ccn.ccnping +
        + nepi.resources.linux.ccn.ccnpingserver +
        + nepi.resources.linux.ccn.ccnpoke +
        + nepi.resources.linux.ccn.ccnr +
        + nepi.resources.linux.ccn.fibentry +
        + nepi.resources.linux.channel +
        + nepi.resources.linux.debfuncs +
        + nepi.resources.linux.gretunnel +
        + nepi.resources.linux.interface +
        + nepi.resources.linux.mtr +
        + nepi.resources.linux.netns +
        + nepi.resources.linux.netns.netnsclient +
        + nepi.resources.linux.netns.netnsemulation +
        + nepi.resources.linux.node +
        + nepi.resources.linux.nping +
        + nepi.resources.linux.ns3 +
        + nepi.resources.linux.ns3.ccn +
        + nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication +
        + nepi.resources.linux.ns3.ccn.ns3ccndceapplication +
        + nepi.resources.linux.ns3.ccn.ns3ccnddceapplication +
        + nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication +
        + nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication +
        + nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication +
        + nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication +
        + nepi.resources.linux.ns3.fdudptunnel +
        + nepi.resources.linux.ns3.ns3client +
        + nepi.resources.linux.ns3.ns3dceapplication +
        + nepi.resources.linux.ns3.ns3pingdceapplication +
        + nepi.resources.linux.ns3.ns3simulation +
        + nepi.resources.linux.ns3.tuntapfdlink +
        + nepi.resources.linux.ping +
        + nepi.resources.linux.route +
        + nepi.resources.linux.rpmfuncs +
        + nepi.resources.linux.tap +
        + nepi.resources.linux.tcpdump +
        + nepi.resources.linux.traceroute +
        + nepi.resources.linux.tun +
        + nepi.resources.linux.tunnel +
        + nepi.resources.linux.udptest +
        + nepi.resources.linux.udptunnel +
        + nepi.resources.netns +
        + nepi.resources.netns.netnsapplication +
        + nepi.resources.netns.netnsbase +
        + nepi.resources.netns.netnsclient +
        + nepi.resources.netns.netnsemulation +
        + nepi.resources.netns.netnsinterface +
        + nepi.resources.netns.netnsipv4address +
        + nepi.resources.netns.netnsnode +
        + nepi.resources.netns.netnsnodeinterface +
        + nepi.resources.netns.netnsroute +
        + nepi.resources.netns.netnsserver +
        + nepi.resources.netns.netnsswitch +
        + nepi.resources.netns.netnswrapper +
        + nepi.resources.netns.netnswrapper_debug +
        + nepi.resources.ns3 +
        + nepi.resources.ns3.classes +
        + nepi.resources.ns3.classes.aarf_wifi_manager +
        + nepi.resources.ns3.classes.aarfcd_wifi_manager +
        + nepi.resources.ns3.classes.adhoc_wifi_mac +
        + nepi.resources.ns3.classes.aloha_noack_net_device +
        + nepi.resources.ns3.classes.amrr_wifi_manager +
        + nepi.resources.ns3.classes.ap_wifi_mac +
        + nepi.resources.ns3.classes.arf_wifi_manager +
        + nepi.resources.ns3.classes.arp_l3protocol +
        + nepi.resources.ns3.classes.base_station_net_device +
        + nepi.resources.ns3.classes.binary_error_model +
        + nepi.resources.ns3.classes.binary_error_sixlow_model +
        + nepi.resources.ns3.classes.bridge_channel +
        + nepi.resources.ns3.classes.bridge_net_device +
        + nepi.resources.ns3.classes.bulk_send_application +
        + nepi.resources.ns3.classes.burst_error_model +
        + nepi.resources.ns3.classes.cara_wifi_manager +
        + nepi.resources.ns3.classes.constant_acceleration_mobility_model +
        + nepi.resources.ns3.classes.constant_position_mobility_model +
        + nepi.resources.ns3.classes.constant_rate_wifi_manager +
        + nepi.resources.ns3.classes.constant_speed_propagation_delay_model +
        + nepi.resources.ns3.classes.constant_velocity_mobility_model +
        + nepi.resources.ns3.classes.cost231propagation_loss_model +
        + nepi.resources.ns3.classes.csma_channel +
        + nepi.resources.ns3.classes.csma_net_device +
        + nepi.resources.ns3.classes.drop_tail_queue +
        + nepi.resources.ns3.classes.dsrdsr_routing +
        + nepi.resources.ns3.classes.emu_net_device +
        + nepi.resources.ns3.classes.error_channel +
        + nepi.resources.ns3.classes.error_channel_sixlow +
        + nepi.resources.ns3.classes.error_net_device +
        + nepi.resources.ns3.classes.fd_net_device +
        + nepi.resources.ns3.classes.fixed_rss_loss_model +
        + nepi.resources.ns3.classes.friis_propagation_loss_model +
        + nepi.resources.ns3.classes.gauss_markov_mobility_model +
        + nepi.resources.ns3.classes.hierarchical_mobility_model +
        + nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model +
        + nepi.resources.ns3.classes.icmpv4l4protocol +
        + nepi.resources.ns3.classes.icmpv6l4protocol +
        + nepi.resources.ns3.classes.ideal_wifi_manager +
        + nepi.resources.ns3.classes.ipv4l3protocol +
        + nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model +
        + nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model +
        + nepi.resources.ns3.classes.jakes_propagation_loss_model +
        + nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model +
        + nepi.resources.ns3.classes.list_error_model +
        + nepi.resources.ns3.classes.log_distance_propagation_loss_model +
        + nepi.resources.ns3.classes.loopback_net_device +
        + nepi.resources.ns3.classes.lr_wpan_net_device +
        + nepi.resources.ns3.classes.lte_enb_net_device +
        + nepi.resources.ns3.classes.lte_simple_net_device +
        + nepi.resources.ns3.classes.lte_ue_net_device +
        + nepi.resources.ns3.classes.matrix_propagation_loss_model +
        + nepi.resources.ns3.classes.mesh_point_device +
        + nepi.resources.ns3.classes.mesh_wifi_interface_mac +
        + nepi.resources.ns3.classes.minstrel_wifi_manager +
        + nepi.resources.ns3.classes.multi_model_spectrum_channel +
        + nepi.resources.ns3.classes.nakagami_propagation_loss_model +
        + nepi.resources.ns3.classes.nist_error_rate_model +
        + nepi.resources.ns3.classes.node +
        + nepi.resources.ns3.classes.non_communicating_net_device +
        + nepi.resources.ns3.classes.ocb_wifi_mac +
        + nepi.resources.ns3.classes.oh_buildings_propagation_loss_model +
        + nepi.resources.ns3.classes.okumura_hata_propagation_loss_model +
        + nepi.resources.ns3.classes.on_off_application +
        + nepi.resources.ns3.classes.onoe_wifi_manager +
        + nepi.resources.ns3.classes.packet_sink +
        + nepi.resources.ns3.classes.ping6 +
        + nepi.resources.ns3.classes.point_to_point_channel +
        + nepi.resources.ns3.classes.point_to_point_net_device +
        + nepi.resources.ns3.classes.point_to_point_remote_channel +
        + nepi.resources.ns3.classes.radvd +
        + nepi.resources.ns3.classes.random_direction2d_mobility_model +
        + nepi.resources.ns3.classes.random_propagation_delay_model +
        + nepi.resources.ns3.classes.random_propagation_loss_model +
        + nepi.resources.ns3.classes.random_walk2d_mobility_model +
        + nepi.resources.ns3.classes.random_waypoint_mobility_model +
        + nepi.resources.ns3.classes.range_propagation_loss_model +
        + nepi.resources.ns3.classes.rate_error_model +
        + nepi.resources.ns3.classes.receive_list_error_model +
        + nepi.resources.ns3.classes.red_queue +
        + nepi.resources.ns3.classes.rraa_wifi_manager +
        + nepi.resources.ns3.classes.simple_channel +
        + nepi.resources.ns3.classes.simple_net_device +
        + nepi.resources.ns3.classes.single_model_spectrum_channel +
        + nepi.resources.ns3.classes.six_low_pan_net_device +
        + nepi.resources.ns3.classes.sta_wifi_mac +
        + nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model +
        + nepi.resources.ns3.classes.subscriber_station_net_device +
        + nepi.resources.ns3.classes.tap_bridge +
        + nepi.resources.ns3.classes.tcp_l4protocol +
        + nepi.resources.ns3.classes.three_log_distance_propagation_loss_model +
        + nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model +
        + nepi.resources.ns3.classes.uan_channel +
        + nepi.resources.ns3.classes.udp_client +
        + nepi.resources.ns3.classes.udp_echo_client +
        + nepi.resources.ns3.classes.udp_echo_server +
        + nepi.resources.ns3.classes.udp_l4protocol +
        + nepi.resources.ns3.classes.udp_server +
        + nepi.resources.ns3.classes.udp_trace_client +
        + nepi.resources.ns3.classes.v4ping +
        + nepi.resources.ns3.classes.virtual_net_device +
        + nepi.resources.ns3.classes.waypoint_mobility_model +
        + nepi.resources.ns3.classes.wifi_net_device +
        + nepi.resources.ns3.classes.yans_error_rate_model +
        + nepi.resources.ns3.classes.yans_wifi_channel +
        + nepi.resources.ns3.classes.yans_wifi_phy +
        + nepi.resources.ns3.ns3application +
        + nepi.resources.ns3.ns3arpl3protocol +
        + nepi.resources.ns3.ns3base +
        + nepi.resources.ns3.ns3ccndceapplication +
        + nepi.resources.ns3.ns3channel +
        + nepi.resources.ns3.ns3client +
        + nepi.resources.ns3.ns3dceapplication +
        + nepi.resources.ns3.ns3dcehelper +
        + nepi.resources.ns3.ns3errormodel +
        + nepi.resources.ns3.ns3errorratemodel +
        + nepi.resources.ns3.ns3fdnetdevice +
        + nepi.resources.ns3.ns3icmpv4l4protocol +
        + nepi.resources.ns3.ns3ipv4l3protocol +
        + nepi.resources.ns3.ns3mobilitymodel +
        + nepi.resources.ns3.ns3netdevice +
        + nepi.resources.ns3.ns3node +
        + nepi.resources.ns3.ns3pipechanel +
        + nepi.resources.ns3.ns3propagationdelaymodel +
        + nepi.resources.ns3.ns3propagationlossmodel +
        + nepi.resources.ns3.ns3queue +
        + nepi.resources.ns3.ns3route +
        + nepi.resources.ns3.ns3server +
        + nepi.resources.ns3.ns3simulation +
        + nepi.resources.ns3.ns3wifichannel +
        + nepi.resources.ns3.ns3wifimac +
        + nepi.resources.ns3.ns3wifinetdevice +
        + nepi.resources.ns3.ns3wifiphy +
        + nepi.resources.ns3.ns3wifiremotestationmanager +
        + nepi.resources.ns3.ns3wrapper +
        + nepi.resources.ns3.ns3wrapper_debug +
        + nepi.resources.ns3.resource_manager_generator +
        + nepi.resources.omf +
        + nepi.resources.omf.application +
        + nepi.resources.omf.channel +
        + nepi.resources.omf.interface +
        + nepi.resources.omf.messages_5_4 +
        + nepi.resources.omf.messages_6 +
        + nepi.resources.omf.node +
        + nepi.resources.omf.omf5_api +
        + nepi.resources.omf.omf6_api +
        + nepi.resources.omf.omf6_parser +
        + nepi.resources.omf.omf_api_factory +
        + nepi.resources.omf.omf_client +
        + nepi.resources.omf.omf_resource +
        + nepi.resources.omf.wilabt_node +
        + nepi.resources.planetlab +
        + nepi.resources.planetlab.node +
        + nepi.resources.planetlab.ns3 +
        + nepi.resources.planetlab.ns3.fdudptunnel +
        + nepi.resources.planetlab.ns3.tuntapfdlink +
        + nepi.resources.planetlab.openvswitch +
        + nepi.resources.planetlab.openvswitch.ovs +
        + nepi.resources.planetlab.openvswitch.ovsport +
        + nepi.resources.planetlab.plcapi +
        + nepi.resources.planetlab.sfa_node +
        + nepi.resources.planetlab.tap +
        + nepi.resources.planetlab.tun +
        + nepi.resources.planetlab.vroute +
        + nepi.util +
        + nepi.util.environ +
        + nepi.util.execfuncs +
        + nepi.util.guid +
        + nepi.util.logger +
        + nepi.util.manifoldapi +
        + nepi.util.netgraph +
        + nepi.util.parallel +
        + nepi.util.parsers +
        + nepi.util.parsers.xml_parser +
        + nepi.util.plotter +
        + nepi.util.rmatcher +
        + nepi.util.serializer +
        + nepi.util.sfaapi +
        + nepi.util.sfarspec_proc +
        + nepi.util.sshfuncs +
        + nepi.util.statfuncs +
        + nepi.util.timefuncs +
    + + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/search.html b/doc/sphinx/_build/html/search.html new file mode 100644 index 00000000..fff7c622 --- /dev/null +++ b/doc/sphinx/_build/html/search.html @@ -0,0 +1,105 @@ + + + + + + + + Search — NEPI 3.0 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +
    +
    +
    + +

    Search

    +
    + +

    + Please activate JavaScript to enable the search + functionality. +

    +
    +

    + From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

    +
    + + + +
    + +
    + +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/searchindex.js b/doc/sphinx/_build/html/searchindex.js new file mode 100644 index 00000000..163da033 --- /dev/null +++ b/doc/sphinx/_build/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({envversion:42,terms:{get_slice_resourc:16,get_object:[20,6],wait_start:10,prefix:[16,1],wait_local_port:8,nthread:10,concret:10,ns3ccnpeekdceappl:[8,12,1,21],linuxccnpok:0,ns3basestationnetdevic:11,everi:16,do_releas:[8,1,19,9,2,10,13,4],ns3subscriberstationnetdevic:11,manifoldapi:[12,17],ns3fdnetdevic:[12,21],cmd:[16,1],upload:[1,4],netns_vers:2,sliceid:4,verif:[4,9],enable_trac:10,ns3randompropagationdelaymodel:11,histor:3,consequ:10,second:[10,16,4],aggreg:[3,16],linuxtcpdump:1,udp_l4protocol:[12,21,6],even:1,ns3pingdceappl:[12,1,21],messages_6:[12,21],omf6_api:[12,21],introspect:6,adhoc:16,ns3apwifimac:11,"new":[10,16,4],net:[1,4],topolog:[3,16],ovsswitch:19,linuxp:1,controlmast:16,omfappl:4,ns3fixedrsslossmodel:11,path:[0,8,1,2,10,16,3,4,22],taskstatu:10,ns3udpl4protocol:11,okumura_hata_propagation_loss_model:[12,21,6],unreserve_host:9,datetim:16,endpoint_mkdir:[8,1],realeas:10,sdate:16,countn:3,unix:4,linuxnod:[1,9],plot:[10,16],describ:10,would:1,omf_resourc:[12,21],call:[10,16,4,9],ns3dcehelp:[12,21],type:[19,10,13,16,4,23],until:[8,1,9,2,10,16,4],heappop:10,ns3constantvelocitymobilitymodel:11,relat:[10,1,6],notic:[1,4],warn:16,parse_fil:[3,22],get_platform:10,register_resourc:10,hold:[16,1],yans_wifi_phi:[12,21,6],uploadin:1,must:[10,16,1],join:16,err:[16,1],pid:[16,1,6],work:[16,1],spec:16,server_kei:16,get_provision_tim:10,upload_start_command:[8,0,1,9,2],root:[10,16,4],overrid:10,set_stop:10,unregister_condit:10,indic:16,rgister:10,ns3binaryerrorsixlowmodel:11,want:[1,4],prefixlen:16,ns3loopbacknetdevic:11,end:[16,1,4],fail_sfaapi:[4,9],how:1,sever:10,env:[16,1,4],peer_map:9,udp_serv:[12,21,6],src_dir:[8,1,2],config:16,connect_timeout:[16,1,4],ns3mobilitymodel:[12,21],confid:10,ns3tapbridg:11,ladder:16,after:[10,16,19,4,9],openvswitch:[12,21,9],lab:9,befor:[10,16,1,19],mesh:16,arch:9,parallel:[12,17],slice_id:16,clean_hom:1,ns3server:[12,21],credenti:[10,16,4],content_histori:3,receiv:[10,4],environ:[12,1,17,4],order:[10,16,4],netn:[12,1,21],sta_wifi_mac:[12,21,6],ocb_wifi_mac:[12,21,6],uuid:[20,6],reserve_resourc:16,filter_existing_fil:1,select_target_zero:16,persist:[10,16,1,4],cred:4,them:10,thei:[16,1,4],bootstrapf:9,safe:[10,16],ostyp:1,stop_with_condit:10,maxqueu:16,interrupt:10,wait_releas:10,min_run:10,pformat:16,each:[10,3,4,9,16],debug:[16,1,20,6],linuxtun:1,mean:[10,1,4],onoe_wifi_manag:[12,21,6],myslic:16,range_propagation_loss_model:[12,21,6],pl_user:9,point_to_point_net_devic:[12,21,6],csma_net_devic:[12,21,6],upload_sourc:[7,8,1,9,2],collector:[12,21],network:[10,16],dst:1,linuxns3cli:8,content:17,nito:4,linear:16,use_rpm:1,free:10,standard:16,netnswrappermessag:20,sigkil:16,fcdistro:9,store_path:13,linuxccncat:0,experimentid:4,filter:[10,16,9],unabl:1,lte_ue_net_devic:[12,21,6],onto:16,rang:10,netns_src:2,edge_net_annot:16,clsinit_copi:10,independ:10,restrict:10,hook:4,instruct:1,get_o:1,messag:[10,3,4],ns3tworaygroundpropagationlossmodel:11,sleekxmpp:4,consol:1,log_funct:4,tool:[16,1],wlab17:4,alreadi:[10,16,1],pl_host:9,set_ec_failur:10,target:[16,4],keyword:9,provid:[10,3,1],tree:16,"final":10,assign_control:19,provis:[10,16,4,9],ns3errormodel:[12,21],ccn_client_helper_uuid:6,runner:[12,17],execute_command:1,ns3lteenbnetdevic:11,wait_pid:1,log_distance_propagation_loss_model:[12,21,6],recreat:10,linuxappl:[0,8,1,19,2,9],ns3simul:[12,1,21],fname:3,lte_simple_net_devic:[12,21,6],ns3wrapper:[12,21],port_numb:19,usernam:[16,9],ns3channel:[12,21],register_typ:10,mesh_point_devic:[12,21,6],planetlabovsport:19,don:4,random_propagation_loss_model:[12,21,6],doe:[10,16,19,9],dump_factori:[20,6],get_help:10,declar:10,release_tim:10,dot:16,frcp_configur:4,servers_on:19,random:16,dirpath:[10,16],get_resourc:10,hybrid_buildings_propagation_loss_model:[12,21,6],find_typ:10,fail_node_not_al:[4,9],involv:10,absolut:[10,16],udp_trace_cli:[12,21,6],explain:[],configur:[10,0,4,8],stanza:4,than:10,modenapl:16,busi:1,folder:[10,16,1],timefunc:[12,17],create_ns3_rm:6,resourcemang:10,stop:[6,8,1,19,2,10,4],sfaapi:[12,17,4,9],udptunnel:[12,21],report:10,ideal_wifi_manag:[12,21,6],symmetr:10,ns3_set:6,omf5_api:[12,21],ns3constantpositionmobilitymodel:11,method:[6,1,9,10,20,16,4],check_releas:4,human:10,multi_model_spectrum_channel:[12,21,6],result:[10,16,1],ns3aarfcdwifimanag:11,respons:[10,1],fail:10,fd_net_devic:[12,21,6],dsrdsr_rout:[12,21,6],subject:10,discoveri:10,endpoint_nod:8,figur:[10,16],ns3applic:[12,21],dce_application_lock:6,udp_echo_cli:[12,21,6],res_id:4,remote_span:16,attribut:[12,17],accord:16,omf:[10,12,21],ns3_src_locat:8,ns3basemobilitymodel:[11,6],get_p2p_info:16,ovsport:[12,21,9],omf6_pars:[12,21],oml:16,extens:[10,5,9],advertis:16,ns3_build_loc:8,howev:[10,16],lte_enb_net_devic:[12,21,6],login:[16,9],strict_host_check:[16,1,4],ns3bridgechannel:11,slice_tag_id:9,nicta:4,guid:[0,6,7,8,12,1,19,9,2,10,13,11,14,17,4,20],assum:[10,16],ns3listerrormodel:11,xmldecod:23,been:[10,16,4],enrol:4,gre_en:1,terminate_connect:[8,1,19],unsubscrib:4,ns3basenetdevic:[11,6],basic:10,endpoint1:[8,1],endpoint2:[8,1],csma_channel:[12,21,6],run_serv:[20,6],hpcbench:1,xml_parser:[16,12],ani:[10,1,4,9],ns3basearpl3protocol:[11,6],blacklist_resourc:16,child:[10,4],get_opt:[20,6],dce_manager_lock:6,ident:16,servic:[16,9],properti:[16,4,9],sourceforg:1,sfarspecprocess:16,check_readi:4,spawn:[16,1],applic:[10,12,21],"0x7f028ff15bb0":16,set_discov:10,ityp:4,kwarg:[6,8,2,10,20,16],make_dict_rec:16,conn:[20,6],sfa_nod:[12,21],ccnr:[12,1,21],perform:10,make:[10,16],ccnd:[3,12,1,21],complex:9,configure_ip:4,ns3friispropagationlossmodel:11,complet:[10,9],parse_sfa_rspec:16,do_deploi:[0,6,8,1,19,9,2,10,13,4,20],nid:[3,16],rais:10,enable_dc:8,ns3_wrapper:6,ns3dceapplic:[12,1,21],netnswrapp:[12,21],redefin:10,scenario:10,inherit:10,client:[6,1,9,20,16,4],get_slice_vnet_sys_tag:9,thi:[5,6,1,9,10,20,16,4],install_depend:1,tcp_l4protocol:[12,21,6],protocol:4,linuxns3dceappl:8,ns3baseipv4l3protocol:[11,6],initiate_connect:[8,1],yet:[16,4],expos:10,character:10,save:[10,16,1],adress:4,noop_funct:4,mayb:16,preserv:1,ns3threelogdistancepropagationlossmodel:11,ns3ccncatdceappl:[8,12,1,21],background:[16,1],dce_vers:8,measur:[10,1],daemon:1,specif:[10,1,4],manual:1,fail_discoveri:[4,9],ns3okumurahatapropagationlossmodel:11,dce_application_uuid:6,fedora_12:1,fedora_14:1,negat:9,interv:10,recv_msg:[20,6],intern:16,clean_experi:1,planetlabtun:9,set_provis:10,subclass:10,get_trac:10,ns3basefdnetdevic:[11,6],condit:10,localhost:1,start_multical:9,core:[],plu:16,ssh_config:16,ple:[16,9],plc:9,unregister_connect:10,peer:9,get_nod:9,guidgener:16,obj:16,tdiffsec:16,make_kei:16,simul:[8,5,6,10,2],timestamp2:16,timestamp1:16,produc:10,ns3basedceappl:[8,6],shell_escap:16,newuuid:[20,6],"float":10,encod:16,www:9,node_ip_annot:16,separet:1,often:4,ns3sixlowpannetdevic:11,wai:[16,1,4,9],support:[10,16,1,9],transform:10,avail:[10,1,19],ap_wifi_mac:[12,21,6],gil:10,tcpdump:[12,21],fork:1,matrix_propagation_loss_model:[12,21,6],medium:1,minstrel_wifi_manag:[12,21,6],form:10,forc:[10,16,1],run_hom:[8,1],raise_on_error:1,heap:10,"true":[10,16,1,4],flavour:9,attr:[0,6,8,1,10,20,4],set_with_condit:10,mtr:[12,21],maximum:10,mtu:1,ecxmlpars:23,tsformat:16,ns3nisterrorratemodel:11,fixed_rss_loss_model:[12,21,6],featur:16,netnsipv4rout:20,configure_ifac:4,get_resource_urn:16,diagnost:16,workerthread:16,exist:[1,19,10,9,16,4],check:[1,19,10,9,16,4],from_typ:23,verify_connect:[8,1,19],steady_state_random_waypoint_mobility_model:[12,21,6],ns3baseicmpv4l4protocol:[11,6],when:[10,16,1,4],annotate_cn_nod:[3,22],test:[16,9],ns3node:[12,21],node:[10,3,12,21],traceattr:10,consid:10,to_typ:23,emu_get:20,longer:10,emu_net_devic:[12,21,6],create_hom:[16,1],exp_hom:1,time:[10,16,4,9,6],resource_urn:16,uan_channel:[12,21,6],annotate_node_ip:16,simple_net_devic:[12,21,6],concept:10,skip:10,consum:3,focus:4,create_and_enroll_top:4,fail_not_enough_nod:[4,9],remote_statu:16,netnsswitch:[12,21],decid:10,depend:[1,4,9],graph:[10,3,22,16],readabl:10,node_count:16,sourc:[0,13,5,7,6,1,19,9,2,10,16,23,11,8,3,14,4,22,20],string:[10,16,1,9],ns3receivelisterrormodel:11,wait_run:1,pl_pass:9,add_set_hook:[1,4],level:[10,16,20,4,6],get_rtyp:10,connection_app_hom:[1,19,9],upload_fil:1,filter_resourc:10,channeltofreq:4,receive_list_error_model:[12,21,6],ns3constantaccelerationmobilitymodel:11,arf_wifi_manag:[12,21,6],ns3ccnddceapplic:[8,12,1,21],port:[8,1,4,19,16],del_edge_annot:16,establish_connect:[8,1],repli:[16,20,6],current:[10,16,4,19],stformat:16,ovs_statu:19,deriv:10,udp_echo_serv:[12,21,6],old_valu:4,gener:[10,8,1,4,9],cara_wifi_manag:[12,21,6],satisfi:10,address:[10,8,4,16],use_deb:1,wait:[8,1,19,2,10,9],box:[16,4],check_mailbox:4,sfi_sm:16,plotter:[12,17],netgraph:[10,12,17],queue:[10,16,6],trial:1,yans_error_rate_model:[12,21,6],environn:4,linuxnetnscli:2,generate_topolog:16,prefer:10,backtick:16,instal:[1,9],mobil:6,ipv4l3protocol:[12,21,6],live:[5,1],criteria:10,msg:[10,8,1,16],scope:[10,1],ppid:[16,1],ns3steadystaterandomwaypointmobilitymodel:11,send_repli:[20,6],ip2:16,plexu:4,ip1:16,ip6:1,ip4:1,exp_id:[10,4],ccncat:[12,1,21],three_log_distance_propagation_loss_model:[12,21,6],uniqu:[10,16,4],cat:1,can:[10,16,1,4],deploy_with_condit:10,process_content_histori:3,purpos:10,get_resources_info:16,stream:10,ns3randomwalk2dmobilitymodel:11,eval_failur:10,topic:4,critic:10,abort:10,occur:[10,16,1],alwai:1,dump_head:[20,6],unimo:16,multipl:[10,16],annotate_edg:16,check_statu:[1,19],ns3radvd:11,ping:[12,15,18],purg:4,create_port:19,map:[16,9],stdin_funct:4,mac:1,nitlab:4,two_ray_ground_propagation_loss_model:[12,21,6],date:[10,16,4],data:[12,17],ns3arfwifimanag:11,vif_name_fil:9,stdin:[16,1,4],assign_p2p_ip:16,inform:[6,9,10,16,3,4],"switch":[10,20,19],block:[0,6,8,1,10,20,16,4],callabl:16,replace_path:[8,1,2],tty:[16,1,4],ns3wifiremotestationmanag:[12,21],still:[16,1],entiti:[10,13],jid:4,group:[10,16],polici:10,ns3wrappermessag:6,ns3propagationlossmodel:[12,21],platform:[10,16],mail:4,plcapi:[12,21],non:1,ns3randomdirection2dmobilitymodel:11,initi:[10,8,4],remove_resourc:10,select_base_class:6,verifi:8,now:4,list_error_model:[12,21,6],ns3ccnpokedceappl:[8,12,1,21],name:[0,6,8,1,9,2,10,20,16,3,4],separ:10,initiate_udp_connect:[1,19],x11:1,netnsclient:[12,1,21],ns3bulksendappl:11,compil:1,ns3rateerrormodel:11,udp_connect:1,replac:[8,1,2],continu:[10,16,1],newval:1,happen:[16,1],error_channel:[12,21,6],ns3constantspeedpropagationdelaymodel:11,subnet:16,ccn_produc:3,type_nam:[20,6],resource_hrn:16,cipher_kei:[8,1,19],oldval:1,factori:[8,16,6],resource_typ:10,ns3amrrwifimanag:11,urlpattern:[16,9],ns3errorchannelsixlow:11,get_start_tim:10,"byte":10,care:[10,16,1],ns3udptracecli:11,frequenc:4,synchron:1,turn:19,log_messag:[10,8,1,16],first:[10,16,1],oper:[10,20,6],do_fail:10,directli:[10,1,4],upload_command:1,onc:16,arrai:9,ns3cost231propagationlossmodel:11,parser:[12,15,18],error_channel_sixlow:[12,21,6],enable_dump:[20,6],custom:[4,9],open:16,size:10,given:[10,16,9],local_port:8,cumul:10,copi:[10,16,1],specifi:[10,16,9],open_socket:6,blacklist:[16,9],reserved_tim:10,ns3baseccndceappl:[14,6],add_edge_callback:10,ns3ccnrdceapplic:[8,12,1,21],tuntapfdlink:[12,1,21],sasl_mech:4,lkill:16,get_node_info:9,classmethod:[10,16,4,9],python_passfd_src:2,ressourc:10,were:10,tophat:16,ns3idealwifimanag:11,dump_to_script:[20,6],argument:[10,16,4,9],parallelrun:16,inform_failur:10,do_discov:[10,1,4,9],destroi:16,note:[1,9],ideal:16,omfnod:4,take:[10,16,1],advis:16,burst_error_model:[12,21,6],dump_get:[20,6],noth:[16,4],channel:[12,21],del_node_annot:16,begin:10,sure:16,trace:[12,17],normal:[10,1],track:[10,16],set_ec:10,ns3carawifimanag:11,set_glob:10,date2:16,pair:16,remove_packag:1,wilabtsfanod:4,ns3ping6:11,omf5:4,fdnetdevic:[7,8,6],later:[1,4],runtim:1,put_nowait:16,ns3basewifinetdevic:[11,6],start_with_condit:10,topologytyp:16,show:[10,16],get_failed_tim:10,netnsnod:[12,21],itu_r1411nlos_over_rooftop_propagation_loss_model:[12,21,6],xml:[10,16,23],onli:[1,19,10,9,16,4],explicitli:[10,1],state:[0,6,8,1,10,20,4],dict:[16,4],rspec_str:16,get:[6,8,1,9,2,10,19,16,4,20],repo:2,ssl:4,create_funct:4,ssh:[16,19,1,4,9],is_sourc:16,requir:[10,16,1],yield:10,upload_stdin:1,ns3lrwpannetdevic:11,make_control_path:16,where:[16,1,19],format_arg:[20,6],rexec:16,from_xml:23,msg_type:[8,6,20,2],fail_plapi:9,concern:4,date1:16,upload_cod:1,ns3baseappl:[11,6],parent:[10,16,4],ns3icmpv4l4protocol:[12,21],enumer:10,enough:10,ns3fibentrydceappl:[8,12,1,21],between:10,"import":[10,1],cmdlinearg:4,create_socket:20,amtogatewai:4,get_glob:10,ns3droptailqueu:11,tun:[12,21],remote_socket:[8,2],mani:[10,1],with_lock:1,mesh_wifi_interface_mac:[12,21,6],format_environ:1,ns3constantratewifimanag:11,colon:1,deploi:[10,1,4,19],binary_error_model:[12,21,6],get_ready_tim:10,ns3onoewifimanag:11,mark:[10,16],breath:16,omfresourc:4,state_time_attr:10,plapi:9,repons:13,newexp_funct:4,reschedul:10,do_provis:[6,19,1,13,10,9,4,20],ns3minstrelwifimanag:11,linuxns3dcefibentri:14,single_model_spectrum_channel:[12,21,6],prefixt:16,local_endpoint:19,linuxudptunnel:[8,1],gretunnel:[12,21],ns3multimodelspectrumchannel:11,experimentrunn:[10,5],set_hook:10,"case":[16,4],sfi_us:16,ovswitch:19,linuxrout:1,linuxns3dceccnpok:14,exec_run_hom:9,cast:23,invok:[10,8,6,20,2],invoc:[16,1,4],arp_l3protocol:[12,21,6],ccnapplic:[12,1,21],virtual_net_devic:[12,21,6],add_slice_nod:9,stdout:[16,1],metric:10,destin:[16,1,4],lr_wpan_net_devic:[12,21,6],ns3yanswifiphi:11,initialize_work:16,rmatcher:[12,17],dce_src_loc:8,same:[1,13,10,9,16,4],binari:1,ns3rraawifimanag:11,finish:[16,1,4],evaluate_convergence_callback:10,dump_stop:6,escape_quot:4,driver:5,check_sliver_ov:19,capabl:10,ns3bursterrormodel:11,finish_multical:9,ready_tim:10,ns3csmachannel:11,execute_deploy_command:1,load_content_histori:3,ccn:[12,15,18],disassoci:10,rpmfunc:[12,21],linuxccnd:0,manifold:16,execut:[12,17],allowed_typ:6,failed_tim:10,kill:[16,1,4],linuxccnr:0,get_slic:9,linuxccnp:0,flavor:1,struct:9,get_resources_hrn:16,except:1,param:[10,16,9],get_slice_tag:9,forward_x11:[16,1,4],newexp:4,ns3errornetdevic:11,drop_tail_queu:[12,21,6],read:[10,1],tid:[10,6],dbase:16,xmpp_root:4,get_frequ:4,delayed_except:16,integ:[10,1],server:[16,1,4,19],red_queu:[12,21,6],either:[10,16,1,4],appid:4,output:[16,1],manag:[10,5,16],is_valid_valu:10,format_kwarg:[20,6],ns3netdevic:[12,21],constant_speed_propagation_delay_model:[12,21,6],adequ:10,ns3wifiphi:[12,21],planetlabovsswitch:19,slice:[16,4,9],confirm:4,linuxns3simul:8,set_target:16,level_nam:4,exit:[10,1,4],nodefamili:9,linuxchannel:1,tapnod:8,do_stop:[0,6,8,1,9,2,10,20,4],add_resource_to_slice_batch:16,is_target:16,timeout:16,share_dir:1,logs_dir:[3,22],"throw":1,src:[1,4,2],select_random_sourc:16,central:16,netnsipv4address:[12,21],register_connect:10,establish_udp_connect:[1,19],shra:4,omfchannel:4,unregist:4,remove_packages_command:1,constant_rate_wifi_manag:[12,21,6],stare:16,log:[10,3,4,16],area:9,alias_funct:4,overwrit:1,start:[6,8,1,19,2,10,16,4],interfac:[10,12,21],rmdir:1,iff_tap:1,tupl:16,recv_fd:6,friis_propagation_loss_model:[12,21,6],netnsinterfac:[12,21],possibl:[10,1,4,19],"default":[10,16,4,9],uid:4,creat:[6,8,1,9,2,10,19,16,4,20],certain:10,file:[8,1,9,10,16,3,4,22],planetlabvrout:9,orient:[],field:[16,9],valid:[10,16],nakagami_propagation_loss_model:[12,21,6],you:[16,1,4],architectur:4,registri:9,python_unshare_src:2,ns3baseerrorratemodel:[11,6],dump_invok:[20,6],remote_kil:16,linuxinterfac:1,directori:[10,16,1,13],release_funct:4,wifi:4,descript:10,set_stat:10,escap:[8,1,16,2],bulk_send_appl:[12,21,6],represent:[10,16],all:[10,12,21],remove_resource_from_slic:16,do_connect:10,ns3itur1411lospropagationlossmodel:11,check_error:1,code:[10,5,1,16,8],follow:[10,1,9],scp:16,edg:16,get_node_flavour:9,template_attribut:6,those:[10,1],yans_wifi_channel:[12,21,6],ccnping:[12,1,21],global:[10,9],delete_slice_nod:9,noread:10,fals:[6,1,10,20,16,3,4],sshfunc:[12,17],vif_typ:1,util:[10,12,17,4],clientxmpp:4,load_ns3_modul:6,failur:10,jakes_propagation_loss_model:[12,21,6],nepi_hom:1,list:[7,8,1,9,10,16,4],ec_failur:10,emul:[5,20,2],stderr:[16,1],node1:8,node2:8,ns3wifinetdevic:[12,21],dump_shutdown:[20,6],omf_api_factori:[12,21],sync:16,design:10,pass:[10,16],fail_node_not_avail:[4,9],socket_nam:[8,6,20,2],brief:1,make_server_key_arg:16,configure_funct:4,delet:[16,1,4,19],ns3pipechanel:[12,21],version:[0,4,16,14],"public":16,is_finish:6,full:[10,4],exit_funct:4,send_stdin:4,ns3udpechoserv:11,bin_dir:1,dump_set:[20,6],modifi:10,valu:[6,1,10,20,16,4,23],optionn:9,search:[5,16],ecstat:10,ns3ccndceapplic:[8,12,1,21],unenroll_top:4,ns3pointtopointnetdevic:11,action:10,messagehandl:4,clone_command:2,six_low_pan_net_devic:[12,21,6],rraa_wifi_manag:[12,21,6],compute_mean:16,filenam:[3,1,22,8],establish:8,regist:[10,4],two:[10,1,6],taken:10,more:16,desir:[16,1,4,19],oh_buildings_propagation_loss_model:[12,21,6],ns3wrapperdebug:6,flag:[10,16],particular:16,known:10,set_valu:10,frcp_inform:4,none:[6,8,1,9,2,10,16,4],endpoint:[7,8,1,19],sincron:9,remote_spawn:16,dev:16,histori:3,remain:1,openssh:16,get_slice_id:9,share:[1,4,9],templat:10,ecplott:16,minimum:10,max_run:10,ns3pointtopointchannel:11,interconnect:[7,8,10,6],gwuser:16,procstatu:16,anoth:[10,1],ns3packetsink:11,random_waypoint_mobility_model:[12,21,6],ns3gaussmarkovmobilitymodel:11,ns3randompropagationlossmodel:11,isn:16,resourc:[12,17],cost231propagation_loss_model:[12,21,6],format_valu:[20,6],ns3udpechocli:11,associ:[10,13],rspawn:16,"short":1,connection_run_hom:[1,19,9],caus:16,callback:10,help:10,xmpp:4,vif_type_flag:1,through:[10,4],ns3csmanetdevic:11,paramet:[19,1,13,10,9,16,4],itu_r1411los_propagation_loss_model:[12,21,6],get_valu:10,pend:10,getpid:1,bypass:16,netnsnodeinterfac:[12,21],omf_client:[12,21],"return":[7,8,1,9,10,19,16,3,4],timestamp:[10,4],planetlabsfanod:9,resource_manager_gener:[12,21],framework:16,ns3adhocwifimac:11,detach:1,set_sourc:16,gethostbynam:16,dceapplic:6,ns3ohbuildingspropagationlossmodel:11,sfaapifactori:16,sock_nam:1,wait_deploi:10,fulli:9,lib_dir:1,load_configur:1,ns3basechannel:[11,6],realli:1,connect:[6,1,19,10,20,16,4],handle_messag:[20,6],event:4,provision_tim:10,item:4,enroll_host:4,publish:4,lstatu:16,print:19,foreground:1,qualifi:9,proxi:9,random_propagation_delay_model:[12,21,6],ns3onoffappl:11,reason:10,base:[0,6,7,8,1,19,9,2,10,23,13,16,11,14,4,20],clazznam:[20,6],put:[16,4],bash:1,planetlabns3fdudptunnel:7,thread:[10,16,4,9,6],launch:1,retriv:1,edge_annot:16,reserve_host:9,assign:[10,16,19],wait_finish:10,number:[10,8,4,16],xmppp:4,done:[10,16],do_start:[0,6,8,1,9,2,10,20,4],jabber:4,baseomfcli:4,differ:[10,16,1,4],script:1,interact:[10,1],linuxns3dceccnr:14,construct:[10,16,20,6],gauss_markov_mobility_model:[12,21,6],linuxdcep:8,linuxns3dceccncat:14,linuxns3dceccnd:14,store:[10,16,1],option:[16,1,9],relationship:10,get_slice_nod:9,part:[10,1],pars:[3,16],remot:[8,1,16,2],remov:[10,16,1],local_p:9,random_walk2d_mobility_model:[12,21,6],bridg:19,str:[10,16,4,9,23],expid:4,comput:[10,3,16],set_releas:10,omfwifiinterfac:4,packag:17,netnsserv:[12,21],"null":16,ns_log:6,annotate_nod:16,lib:1,self:[10,1],also:[16,1],without:[16,4],build:[16,1,4],vif_nam:9,distribut:10,get_resource_typ:10,planetlab:[10,12,21],previou:16,reach:10,ns3rout:[12,21],stdin_hook:4,node_id:[9,6],app_hom:[8,1],ns3noncommunicatingnetdevic:11,parse_ping_log:3,loopback_net_devic:[12,21,6],exp:1,execfunc:[12,17],linuxnp:1,netnswrapperdebug:20,debfunc:[12,21],heapq:10,ns3wifimac:[12,21],session:[16,4],networkx:16,ns3basewifichannel:[11,6],find:10,access:10,wifi_net_devic:[12,21,6],quer:16,evaluate_normal_converg:10,random_direction2d_mobility_model:[12,21,6],unus:4,express:[10,16],nativ:9,configure_on_omf5:4,configure_on_omf6:4,aarfcd_wifi_manag:[12,21,6],ns3icmpv6l4protocol:11,iff_tun:1,ns3basepropagationlossmodel:[11,6],netnsemul:[12,1,21],common:[20,4,6],set_start:10,planetlabtap:9,arp:6,linuxtunnel:1,locali:16,get_endpoint:[7,8,1],point_to_point_remote_channel:[12,21,6],see:16,linuxccnappl:0,arg:[6,8,1,13,2,10,19,16,4,20],reserv:[10,16,9],resourceact:10,ns3udpclient:11,reus:16,fibentri:[12,1,21],subscript:4,experi:[5,1,13,10,19,16,4],xmppclient:4,valid_connect:[0,8,1,19,9,2,10,13,4],numer:[10,9],to_xml:23,network_typ:9,tnow:16,ecseri:16,ns3simplenetdevic:11,install_packag:1,run_dir:10,clsinit:10,load:[10,16],run_id:10,instanti:10,schedul:[12,17],do_reserv:10,home_dir:1,linuxtracerout:1,shutdown:[10,8,6,20,2],linux:[10,12,21],backend:16,guid1:10,guid2:10,adhoc_wifi_mac:[12,21,6],devic:[7,8,1,9,6],empti:16,find_box:16,netnsappl:[12,21],ns3basewifiphi:[11,6],linuxns3ccndceappl:14,slice_id_or_nam:9,imag:[4,9],rspec:16,is_control:3,func:[10,16],blacklist_host:9,ns3jakespropagationlossmodel:11,look:[10,16],batch:16,"while":[10,1],behavior:[10,1,4],error:[10,16,1,19],python_passfd_repo:2,readi:[10,4],omf5api:4,origin:4,netnsbas:[12,21],itself:19,manifoldapifactori:16,bwlimit:[8,1,19],get_resources_by_typ:10,decor:10,fedora:1,belong:10,resolve_hostnam:16,sliver:[16,19],ns3tcpl4protocol:11,content_nam:3,rcopi:16,moment:[10,4],temporari:16,user:[10,16,1,4,9],lgetpid:16,find_hom:1,implement:[10,4],subpackag:17,openssh_has_persist:16,travers:16,task:[10,16,1],replace_arg:[20,6],older:16,wait_vif_nam:9,explan:1,ns3wrapper_debug:[12,21],app_id:4,udptest:[12,21],planetlabnod:9,close_socket:6,enrollkei:4,linuxccnpingserv:0,"0x7f0290310f90":6,input:[16,1],point_to_point_channel:[12,21,6],modul:17,bin:1,is_run:6,format:[10,16,1],submodul:[12,15,17,18],tap_bridg:[12,21,6],exp_dir:[10,1],ccn_client_lock:6,semi:1,dce_repo:8,signal:16,upload_extra_sourc:[8,2],elaps:10,collect:[10,22,13],"boolean":[10,19,4,9],frcp_creat:4,has_attribut:10,load_ns3_librari:6,plc_flavour:9,creation:[16,4],some:[16,9],back:4,failure_level:10,unspecifi:9,sampl:[10,16],ns3ltesimplenetdevic:11,ns3simplechannel:11,per:16,prop:4,retri:[16,1,4],reproduc:1,machin:10,object:[6,9,10,20,16,4,23],run:[10,16,1,4,19],has_flag:10,ping6:[12,21,6],gre_connect:[1,9],sfi_registri:16,wait_all_readi:10,from:[10,3,1,4,16],get_release_tim:10,send_msg:[8,2],constraint:16,private_kei:16,idn:16,dump_start:6,ns3kun2600mhzpropagationlossmodel:11,exitcod:1,pythonpath:1,pldistro:9,hrn:[16,4],all_tag:16,devnam:1,nowrit:10,omf6api:4,sock:6,"long":1,set_fail:10,includ:9,forward:1,compute_metric_callback:10,ns3hierarchicalmobilitymodel:11,ns3uanchannel:11,atom:10,line:[16,1],ns3:[12,1,21],info:[16,1,4],cid:4,uth:4,nid1:[16,22],planet:9,set_hook_mtu:1,similar:1,frcp_releas:4,set_state_tim:10,msg_id:4,ns3basequeu:[11,6],doesn:[16,4],repres:[10,16,1,4],lspawn:16,retract:4,filenotfound:1,failtrap:10,sfarspec_proc:[12,17],clean:[1,4],eintr_retri:16,fdnode:8,meaning:[10,4,19],rm_failur:10,linuxns3dceccnpeek:14,frcp_request:4,typeid:6,ns3wifichannel:[12,21],guids1:10,guids2:10,wait_fil:[8,1],exact_tag:16,queri:[10,16],release_api:4,node_annot:16,maxthread:16,is_rm_inst:10,set_hook_up:1,ns3binaryerrormodel:11,get_node_tag:9,send:[16,4],noop:4,sent:4,vlc:4,ns3_repo:8,tri:16,on_off_appl:[12,21,6],do_disconnect:10,myresourcemanag:10,refer:16,ns3basenod:[11,6],check_state_connect:[8,1],ecodefil:1,ns3itur1411nlosoverrooftoppropagationlossmodel:11,unblacklist_host:9,download:1,aloha_noack_net_devic:[12,21,6],pl_ptn:9,index:[10,5,4],resourcest:10,compute_delay_m:16,cell:4,experiment:10,ns3_get:6,icmpv6l4protocol:[12,21,6],get_discover_tim:10,whatev:16,"enum":10,"0x7f028fc193b0":4,vif_prefix:1,linuxns3fdudptunnel:[7,8],ubuntu:1,becom:4,sinc:[10,1,4],host:[5,1,9,10,16,4],corruptfil:1,wait_guid:10,converg:10,chang:[10,4],control:[10,19,1,4,13],set_reserv:10,app:1,bridge_net_devic:[12,21,6],gatewai:4,api:[5,4,9,16],statfunc:[12,17],hierarchical_mobility_model:[12,21,6],rclass:10,commun:4,logger_compon:16,ns3meshpointdevic:11,doubl:10,next:[10,16],ascii_helper_uuid:6,constant_velocity_mobility_model:[12,21,6],usr:1,check_deploi:4,mask4:1,enroll_top:4,mask6:1,comparison:9,subscriber_station_net_devic:[12,21,6],fedora_8:1,agent:16,ns3singlemodelspectrumchannel:11,upload_binari:1,retriev:[10,16,1,9],install_packages_command:1,tunnel:[12,21],alia:4,txqueuelen:[8,1,19],unenrol:4,annot:3,get_resource_info:16,omfapifactori:4,ns3alohanoacknetdevic:11,get_task:10,ns3errorratemodel:[12,21],tap:[12,21],process:[12,18],lock:[4,9,6],sudo:[16,1,4],trace_filepath:1,tag:[12,17],ns3arpl3protocol:[12,21],serial:[10,12,17],dce_manager_uuid:6,delai:[10,22],ccnpoke:[12,1,21],publicid:16,filepath:[10,16],ns3emunetdevic:11,plcapifactori:9,linuxccnpeek:0,instead:[10,16,1,4],linuxfibentri:0,stop_tim:10,overridden:[10,9],remote_check_pid:16,physic:10,alloc:16,non_communicating_net_devic:[12,21,6],loglevel:[20,6],ns3virtualnetdevic:11,element:[10,4],temp:[16,1],allow:[1,19,10,9,16,4],omf6pars:4,ns3basewifiremotestationmanag:[11,6],get_stop_tim:10,planelab:9,trace_en:10,add_edg:16,remote_endpoint:[8,1,19,9],device_helper_uuid:6,nist_error_rate_model:[12,21,6],ccnpingserv:[12,1,21],local_dir:10,populate_factori:10,therefor:10,python:[10,1],python_unshare_vers:2,ns3ocbwifimac:11,ns3aarfwifimanag:11,run_experi:10,rstatu:16,testbedtogatewai:4,get_connect:10,mode:1,wait_tim:10,chunk:10,udp_client:[12,21,6],special:[8,1,9,2,16,4],out:[16,1],variabl:[1,4],python_passfd_vers:2,install_rpmfusion_command:1,linuxgretunnel:1,develop:[],ns3errorchannel:11,identifi:[10,9],suitabl:[4,9],rel:[10,16],statist:10,ns3stawifimac:11,linuxtap:[1,9],ips2nid:[3,22],ns3udpserv:11,constant_position_mobility_model:[12,21,6],dictionari:[10,3,4],releas:[10,16,19,4,9],wilabt_nod:[12,21],xmlencod:23,has_chang:10,could:10,keep:[10,1],heappush:10,not_start:16,known_host:16,lexec:16,netnsrout:[12,21],python_unshare_repo:2,dump_content_histori:3,mai:9,set:[6,8,9,2,10,19,16,4,20],v4ping:[12,21,6],ccndlog:3,mkdir:[16,1],system:[4,9],wrapper:20,attach:[16,1],termin:[10,1],max_depth:16,get_interfac:9,udp:1,shell:[8,1,2],register_condit:10,netnswrapper_debug:[12,21],failurelevel:10,cpython:10,ns3base:[12,21],structur:1,check_output:1,amrr_wifi_manag:[12,21,6],sens:10,dce_help:8,enroll_funct:4,start_tim:10,kun2600mhz_propagation_loss_model:[12,21,6],session_kei:9,correspond:4,linuxnetnsemul:2,have:[10,16,1,6],close:19,need:[10,16,1,4,19],ns3basewifimac:[11,6],binary_error_sixlow_model:[12,21,6],emu_set:20,mcapi:9,rout:[12,21],error_net_devic:[12,21,6],do_configur:10,which:[10,16,1,4,9],interface_id_or_ip:9,instanci:[16,4,9],singl:[10,16,1],create_api:[4,9],unless:16,get_api:[16,4,9],deploy:[10,9],clase:10,discov:[10,4,9],cipher:[8,1,19],node_tag_id:9,sfi:[16,4,9],"class":[0,6,8,12,1,13,2,10,20,14,21],sfa:[16,4,9],build_sfa_rspec:16,ns3ipv4l3protocol:[12,21],url:[16,9],urn:16,gather:[1,4],request:[16,4],set_readi:10,pipe:[16,1,6],pidfil:[16,1],determin:16,text:[10,1],verbos:16,waypoint_mobility_model:[12,21,6],ccnpeek:[12,1,21],get_session_kei:16,redirect:[16,1],upload_librari:1,locat:16,should:[10,16,20,9,6],add_nod:16,wait_result:8,local:[10,16,1,13,9],create_bridg:19,ns3randomwaypointmobilitymodel:11,base_station_net_devic:[12,21,6],wait_remote_socket:[8,2],autom:1,ns3meshwifiinterfacemac:11,enabl:[10,20,6],ns3basepipechannel:6,lala:1,whether:[10,16,1],contain:[10,16,1,9],script_path:[20,6],view:9,node_id_or_hostnam:9,fdudptunnel:[12,1,21],planetlabtuntapfdlink:7,usr_dir:1,make_uuid:[20,6],statu:[10,16,1,19],extend:10,correctli:[4,9],ns3bridgenetdevic:11,pattern:9,inorm:22,written:4,ns3queue:[12,21],ns3v4ping:11,kei:16,update_slic:9,entir:16,disconnect:4,experimentcontrol:[5,1,19,10,13,4],add_resource_to_slic:16,rtype:[10,16,4],ccn_consum:3,messages_5_4:[12,21],plugin_config:4,tracerout:[12,21,22],etc:[10,16,1,4],instanc:[10,16,4,9],sigterm:16,rexitcod:1,complementari:[],arriv:10,respect:1,admin:9,rgetpid:16,quit:[10,16],resourcegatewai:4,compon:10,immedi:1,radvd:[12,21,6],icmpv4l4protocol:[12,21,6],presenc:4,assert:4,"0x7f028fc19a70":9,nping:[12,21],simple_channel:[12,21,6],togeth:16,present:5,replic:10,multi:1,plain:[1,9],remove_all_from_slic:16,defin:[10,4,9],sformat:16,eintr:16,get_attribut:10,ns3matrixpropagationlossmodel:11,ns3hybridbuildingspropagationlossmodel:11,site:16,request_funct:4,linuxccncont:0,clean_process:1,handl:[10,4],slicenam:[16,9],ns3dsrdsrrout:11,ns3waypointmobilitymodel:11,http:[16,1,9],hostnam:[16,4,9],rkill:16,upon:[10,9],discover_tim:10,phy:6,ns3pointtopointremotechannel:11,execute_funct:4,wthat:19,netns_repo:2,linuxudptest:1,well:[],ofr:4,command:[6,8,1,9,2,20,16,4],resourcefactori:10,usual:[10,16],less:10,vrout:[12,21],obtain:10,dump_creat:[20,6],add_node_callback:10,packet_sink:[12,21,6],annotate_cn_graph:[3,22],web:[16,9],ns3redqueu:11,point:16,init_mailbox:4,add:[9,10,16,3,4,22],is_al:1,stabsformat:16,logger:[6,12,10,20,17,4],match:[10,16,9],xmlrpc:9,dest:16,handle_omf_messag:4,ccncontent:[12,1,21],testb:[10,5,4],know:1,password:[16,4,9],recurs:16,like:[16,9],ns3nakagamipropagationlossmodel:11,necessari:[10,16,1],failuremanag:10,page:5,pygccxml_vers:8,lcopi:16,captur:16,nid2:16,rvqueue:16,"export":1,ns3rangepropagationlossmodel:11,flush:[8,6,20,2],home:[16,1],ilabt:4,librari:[16,1,4],rate_error_model:[12,21,6],node_id_or_nam:9,wilab2:4,leas:16,ipv4:6,sequenc:9,linuxtuntapfdlink:[7,8],ns3propagationdelaymodel:[12,21],dce:5,usag:1,omfclient:4,offset:[0,6,8,1,10,20,4],yyyymmddhhmmssffff:16,about:[10,9],actual:[8,1,2],socket:[8,2],wilabt:[16,4],run_and_wait:1,constant_acceleration_mobility_model:[12,21,6],automat:[10,1],guard:4,check_start:4,ns3yanswifichannel:11,imind:4,aarf_wifi_manag:[12,21,6],sfi_auth:16,ns3basepropagationdelaymodel:[11,6],"function":[10,16,1,4,9],ns3yanserrorratemodel:11,subscrib:4,lalal:1,ns3client:[12,1,21],uninstal:1,inlin:1,count:3,made:[10,1],in_foreground:1,reschedule_delai:10,resourcemanag:[5,6,1,13,10,20,4],asynchron:16,topo_typ:16,limit:16,template_trac:6,process_content_history_log:3,otherwis:10,problem:4,ns3lteuenetdevic:11,plugin_whitelist:4,evalu:10,ns3logdistancepropagationlossmodel:11,"int":[19,1,13,10,9,16,4],mask:16,dure:[10,1,19],tdiff:16,bridge_channel:[12,21,6],inf:4,ing:16,detail:[10,9],virtual:10,new_valu:4,node_hom:1,other:[10,5,1],bool:[10,16],branch:16,varieti:10,is_start:6,repeat:10,star:16,heapschedul:10,shfile:1,replace_kwarg:[20,6],ns3baseerrormodel:[11,6],linuxmtr:1,omf_5:4,debian:1,annotate_edge_net:16,reliabl:1,match_tag:16,controlpersist:16},objtypes:{"0":"py:module","1":"py:method","2":"py:function","3":"py:class","4":"py:attribute","5":"py:classmethod"},objnames:{"0":["py","module","Python module"],"1":["py","method","Python method"],"2":["py","function","Python function"],"3":["py","class","Python class"],"4":["py","attribute","Python attribute"],"5":["py","classmethod","Python class method"]},filenames:["_layout/nepi.resources.linux.ccn","_layout/nepi.resources.linux","_layout/nepi.resources.linux.netns","_layout/nepi.data.processing.ccn","_layout/nepi.resources.omf","index","_layout/nepi.resources.ns3","_layout/nepi.resources.planetlab.ns3","_layout/nepi.resources.linux.ns3","_layout/nepi.resources.planetlab","_layout/nepi.execution","_layout/nepi.resources.ns3.classes","_layout/nepi","_layout/nepi.resources.all","_layout/nepi.resources.linux.ns3.ccn","_layout/nepi.data.processing","_layout/nepi.util","_layout/modules","_layout/nepi.data","_layout/nepi.resources.planetlab.openvswitch","_layout/nepi.resources.netns","_layout/nepi.resources","_layout/nepi.data.processing.ping","_layout/nepi.util.parsers"],titles:["nepi.resources.linux.ccn package","nepi.resources.linux package","nepi.resources.linux.netns package","nepi.data.processing.ccn package","nepi.resources.omf package","NEPI modules","nepi.resources.ns3 package","nepi.resources.planetlab.ns3 package","nepi.resources.linux.ns3 package","nepi.resources.planetlab package","nepi.execution package","nepi.resources.ns3.classes package","nepi package","nepi.resources.all package","nepi.resources.linux.ns3.ccn package","nepi.data.processing package","nepi.util package","nepi","nepi.data package","nepi.resources.planetlab.openvswitch package","nepi.resources.netns package","nepi.resources package","nepi.data.processing.ping package","nepi.util.parsers package"],objects:{"":{nepi:[12,0,0,"-"]},"nepi.resources.ns3.classes.hierarchical_mobility_model":{NS3HierarchicalMobilityModel:[11,3,1,""]},"nepi.resources.linux.rpmfuncs":{install_rpmfusion_command:[1,2,1,""],remove_packages_command:[1,2,1,""],install_packages_command:[1,2,1,""]},"nepi.resources.netns.netnsswitch":{NetNSSwitch:[20,3,1,""]},"nepi.resources.linux.route":{LinuxRoute:[1,3,1,""]},"nepi.resources.ns3.classes.matrix_propagation_loss_model":{NS3MatrixPropagationLossModel:[11,3,1,""]},"nepi.util.parsers.xml_parser":{xmlencode:[23,2,1,""],to_type:[23,2,1,""],ECXMLParser:[23,3,1,""],from_type:[23,2,1,""],xmldecode:[23,2,1,""]},"nepi.resources.netns.netnswrapper.NetNSWrapper":{debuger:[20,4,1,""],invoke:[20,1,1,""],get:[20,1,1,""],get_object:[20,1,1,""],create:[20,1,1,""],replace_kwargs:[20,1,1,""],set:[20,1,1,""],make_uuid:[20,1,1,""],shutdown:[20,1,1,""],replace_args:[20,1,1,""],logger:[20,4,1,""]},"nepi.resources.netns.netnsserver.NetNSWrapperMessage":{SET:[20,4,1,""],INVOKE:[20,4,1,""],GET:[20,4,1,""],CREATE:[20,4,1,""],SHUTDOWN:[20,4,1,""],FLUSH:[20,4,1,""]},"nepi.resources.planetlab.plcapi.PLCAPI":{reserved:[9,1,1,""],get_slice_id:[9,1,1,""],delete_slice_node:[9,1,1,""],start_multicall:[9,1,1,""],get_node_tags:[9,1,1,""],api:[9,4,1,""],unblacklist_host:[9,1,1,""],get_slices:[9,1,1,""],get_slice_tags:[9,1,1,""],get_node_flavour:[9,1,1,""],mcapi:[9,4,1,""],peer_map:[9,4,1,""],test:[9,1,1,""],finish_multicall:[9,1,1,""],get_interfaces:[9,1,1,""],get_slice_nodes:[9,1,1,""],blacklist_host:[9,1,1,""],blacklisted:[9,1,1,""],unreserve_host:[9,1,1,""],get_node_info:[9,1,1,""],network_types:[9,4,1,""],get_slice_vnet_sys_tag:[9,1,1,""],release:[9,1,1,""],reserve_host:[9,1,1,""],get_nodes:[9,1,1,""],update_slice:[9,1,1,""],add_slice_nodes:[9,1,1,""]},"nepi.resources.ns3.ns3node.NS3BaseNode":{arp:[6,4,1,""],mobility:[6,4,1,""],devices:[6,4,1,""],simulation:[6,4,1,""],node_id:[6,4,1,""],ipv4:[6,4,1,""],dceapplications:[6,4,1,""]},"nepi.util":{sfaapi:[16,0,0,"-"],netgraph:[16,0,0,"-"],rmatcher:[16,0,0,"-"],plotter:[16,0,0,"-"],manifoldapi:[16,0,0,"-"],sfarspec_proc:[16,0,0,"-"],statfuncs:[16,0,0,"-"],parsers:[23,0,0,"-"],environ:[16,0,0,"-"],execfuncs:[16,0,0,"-"],timefuncs:[16,0,0,"-"],logger:[16,0,0,"-"],guid:[16,0,0,"-"],parallel:[16,0,0,"-"],serializer:[16,0,0,"-"],sshfuncs:[16,0,0,"-"]},"nepi.resources.linux.ccn.ccncontent":{LinuxCCNContent:[0,3,1,""]},"nepi.resources.ns3.classes.bridge_net_device":{NS3BridgeNetDevice:[11,3,1,""]},"nepi.resources.linux.node.ExitCode":{CORRUPTFILE:[1,4,1,""],FILENOTFOUND:[1,4,1,""],OK:[1,4,1,""],ERROR:[1,4,1,""]},"nepi.resources.ns3.classes.arf_wifi_manager":{NS3ArfWifiManager:[11,3,1,""]},"nepi.resources.linux.mtr.LinuxMtr":{upload_start_command:[1,1,1,""],do_deploy:[1,1,1,""],valid_connection:[1,1,1,""],do_start:[1,1,1,""]},"nepi.resources.ns3.classes.packet_sink":{NS3PacketSink:[11,3,1,""]},"nepi.execution.trace.TraceAttr":{PATH:[10,4,1,""],ALL:[10,4,1,""],STREAM:[10,4,1,""],SIZE:[10,4,1,""]},"nepi.resources.netns.netnsnodeinterface.NetNSNodeInterface":{node:[20,4,1,""],"switch":[20,4,1,""],emulation:[20,4,1,""]},"nepi.resources.linux.application.LinuxApplication":{upload_files:[1,1,1,""],upload_code:[1,1,1,""],do_release:[1,1,1,""],pid:[1,4,1,""],trace_filepath:[1,1,1,""],do_start:[1,1,1,""],upload_libraries:[1,1,1,""],valid_connection:[1,1,1,""],upload_binaries:[1,1,1,""],replace_paths:[1,1,1,""],state:[1,4,1,""],run_home:[1,4,1,""],build:[1,1,1,""],do_stop:[1,1,1,""],upload_sources:[1,1,1,""],ppid:[1,4,1,""],node:[1,4,1,""],app_home:[1,4,1,""],trace:[1,1,1,""],execute_command:[1,1,1,""],do_provision:[1,1,1,""],install_dependencies:[1,1,1,""],do_deploy:[1,1,1,""],log_message:[1,1,1,""],in_foreground:[1,4,1,""],execute_deploy_command:[1,1,1,""],upload_stdin:[1,1,1,""],install:[1,1,1,""],upload_start_command:[1,1,1,""]},"nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication":{do_stop:[6,1,1,""],pid:[6,4,1,""],do_start:[6,1,1,""],trace:[6,1,1,""]},"nepi.resources.linux.ccn.ccnpoke":{LinuxCCNPoke:[0,3,1,""]},"nepi.resources.netns.netnsnode":{NetNSNode:[20,3,1,""]},"nepi.resources.ns3.classes.multi_model_spectrum_channel":{NS3MultiModelSpectrumChannel:[11,3,1,""]},"nepi.resources.linux.ccn.fibentry.LinuxFIBEntry":{node:[0,4,1,""],traceroute:[0,4,1,""],valid_connection:[0,1,1,""],trace:[0,1,1,""],ping:[0,4,1,""],ccnd:[0,4,1,""],do_deploy:[0,1,1,""],do_start:[0,1,1,""],upload_start_command:[0,1,1,""],do_stop:[0,1,1,""],configure:[0,1,1,""]},"nepi.data.processing.ping.parser":{annotate_cn_graph:[22,2,1,""],parse_file:[22,2,1,""],annotate_cn_node:[22,2,1,""]},"nepi.resources.ns3.ns3route.NS3Route":{node:[6,4,1,""]},"nepi.util.logger":{Logger:[16,3,1,""]},"nepi.resources.ns3.classes.radvd":{NS3Radvd:[11,3,1,""]},"nepi.resources.linux.tcpdump.LinuxTcpdump":{do_deploy:[1,1,1,""],valid_connection:[1,1,1,""]},"nepi.resources.netns.netnsroute.NetNSIPv4Route":{node:[20,4,1,""],emulation:[20,4,1,""]},"nepi.resources.ns3.classes.cost231propagation_loss_model":{NS3Cost231PropagationLossModel:[11,3,1,""]},"nepi.util.sshfuncs":{rspawn:[16,2,1,""],STDOUT:[16,3,1,""],log:[16,2,1,""],openssh_has_persist:[16,2,1,""],resolve_hostname:[16,2,1,""],rkill:[16,2,1,""],make_server_key_args:[16,2,1,""],gethostbyname:[16,2,1,""],shell_escape:[16,2,1,""],ProcStatus:[16,3,1,""],rexec:[16,2,1,""],eintr_retry:[16,2,1,""],make_control_path:[16,2,1,""],rcopy:[16,2,1,""],rgetpid:[16,2,1,""],rstatus:[16,2,1,""]},"nepi.resources.ns3.classes.subscriber_station_net_device":{NS3SubscriberStationNetDevice:[11,3,1,""]},"nepi.resources.linux.channel":{LinuxChannel:[1,3,1,""]},"nepi.resources.planetlab.ns3.fdudptunnel.PlanetlabNs3FdUdpTunnel":{get_endpoints:[7,1,1,""]},"nepi.resources.linux.traceroute.LinuxTraceroute":{upload_start_command:[1,1,1,""],do_deploy:[1,1,1,""],valid_connection:[1,1,1,""],do_start:[1,1,1,""]},"nepi.resources.linux.ccn.ccnpeek.LinuxCCNPeek":{do_deploy:[0,1,1,""],valid_connection:[0,1,1,""]},"nepi.resources.linux.debfuncs":{remove_packages_command:[1,2,1,""],install_packages_command:[1,2,1,""]},"nepi.resources.ns3.classes.yans_wifi_phy":{NS3YansWifiPhy:[11,3,1,""]},"nepi.resources.linux.route.LinuxRoute":{node:[1,4,1,""],device:[1,4,1,""],do_deploy:[1,1,1,""],do_start:[1,1,1,""],upload_start_command:[1,1,1,""],do_stop:[1,1,1,""],upload_sources:[1,1,1,""]},"nepi.resources.netns.netnsserver":{get_options:[20,2,1,""],NetNSWrapperMessage:[20,3,1,""],run_server:[20,2,1,""],recv_msg:[20,2,1,""],create_socket:[20,2,1,""],handle_message:[20,2,1,""],send_reply:[20,2,1,""]},"nepi.resources.linux.ns3.ccn.ns3ccndceapplication":{LinuxNS3CCNDceApplication:[14,3,1,""]},"nepi.resources.ns3.ns3errorratemodel.NS3BaseErrorRateModel":{node:[6,4,1,""],phy:[6,4,1,""]},"nepi.resources.omf.omf6_api.OMF6API":{frcp_inform:[4,1,1,""],unenroll_topic:[4,1,1,""],disconnect:[4,1,1,""],create_and_enroll_topic:[4,1,1,""],frcp_configure:[4,1,1,""],check_ready:[4,1,1,""],frcp_create:[4,1,1,""],frcp_release:[4,1,1,""],check_mailbox:[4,1,1,""],frcp_request:[4,1,1,""],enroll_topic:[4,1,1,""]},"nepi.resources.planetlab":{node:[9,0,0,"-"],ns3:[7,0,0,"-"],tap:[9,0,0,"-"],vroute:[9,0,0,"-"],sfa_node:[9,0,0,"-"],openvswitch:[19,0,0,"-"],tun:[9,0,0,"-"],plcapi:[9,0,0,"-"]},"nepi.resources.omf.channel.OMFChannel":{valid_connection:[4,1,1,""],get_frequency:[4,1,1,""],do_release:[4,1,1,""],do_deploy:[4,1,1,""],ChannelToFreq:[4,4,1,""],exp_id:[4,4,1,""]},"nepi.resources.netns.netnsapplication":{NetNSApplication:[20,3,1,""]},"nepi.resources.netns.netnsipv4address":{NetNSIPv4Address:[20,3,1,""]},"nepi.execution.resource.ResourceAction":{START:[10,4,1,""],STOP:[10,4,1,""],DEPLOY:[10,4,1,""]},"nepi.resources.planetlab.ns3.fdudptunnel":{PlanetlabNs3FdUdpTunnel:[7,3,1,""]},"nepi.util.serializer":{ECSerializer:[16,3,1,""],SFormats:[16,3,1,""]},"nepi.resources.netns.netnsclient.NetNSClient":{set:[20,1,1,""],invoke:[20,1,1,""],get:[20,1,1,""],create:[20,1,1,""],shutdown:[20,1,1,""],flush:[20,1,1,""]},"nepi.util.sshfuncs.ProcStatus":{NOT_STARTED:[16,4,1,""],RUNNING:[16,4,1,""],FINISHED:[16,4,1,""]},"nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication":{LinuxNS3DceCCNR:[14,3,1,""]},"nepi.resources.ns3.classes.aarf_wifi_manager":{NS3AarfWifiManager:[11,3,1,""]},"nepi.resources.ns3.ns3ccndceapplication.NS3BaseCCNDceApplication":{ccn_client_lock:[6,4,1,""],ccn_client_helper_uuid:[6,4,1,""]},"nepi.resources.ns3.classes.csma_channel":{NS3CsmaChannel:[11,3,1,""]},"nepi.resources.ns3.classes.uan_channel":{NS3UanChannel:[11,3,1,""]},"nepi.resources.linux.ccn.ccnpeek":{LinuxCCNPeek:[0,3,1,""]},"nepi.execution.runner.ExperimentRunner":{evaluate_normal_convergence:[10,1,1,""],run:[10,1,1,""],run_experiment:[10,1,1,""]},"nepi.resources.ns3.ns3icmpv4l4protocol":{NS3BaseIcmpv4L4Protocol:[6,3,1,""]},"nepi.resources.ns3.ns3channel":{NS3BaseChannel:[6,3,1,""]},"nepi.resources.ns3.ns3base":{NS3Base:[6,3,1,""]},"nepi.resources.omf.interface":{OMFWifiInterface:[4,3,1,""]},"nepi.resources.ns3.classes.okumura_hata_propagation_loss_model":{NS3OkumuraHataPropagationLossModel:[11,3,1,""]},"nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger":{format_kwargs:[20,1,1,""],dump_factory:[20,1,1,""],dump_create:[20,1,1,""],dump_shutdown:[20,1,1,""],dump_to_script:[20,1,1,""],enabled:[20,4,1,""],dump_invoke:[20,1,1,""],format_value:[20,1,1,""],dump_header:[20,1,1,""],format_args:[20,1,1,""],script_path:[20,4,1,""],dump_set:[20,1,1,""],dump_get:[20,1,1,""]},"nepi.util.plotter.PFormats":{FIGURE:[16,4,1,""],DOT:[16,4,1,""]},"nepi.resources.ns3.classes.virtual_net_device":{NS3VirtualNetDevice:[11,3,1,""]},"nepi.resources.ns3.classes.ap_wifi_mac":{NS3ApWifiMac:[11,3,1,""]},"nepi.resources.omf.omf_client":{OMFClient:[4,3,1,""],BaseOMFClient:[4,3,1,""]},"nepi.util.statfuncs":{compute_mean:[16,2,1,""]},"nepi.util.manifoldapi.MANIFOLDAPIFactory":{make_key:[16,5,1,""],get_api:[16,5,1,""]},"nepi.execution.runner":{ExperimentRunner:[10,3,1,""]},"nepi.resources.linux.udptunnel.LinuxUdpTunnel":{initiate_connection:[1,1,1,""],verify_connection:[1,1,1,""],establish_connection:[1,1,1,""],log_message:[1,1,1,""],terminate_connection:[1,1,1,""],get_endpoints:[1,1,1,""],check_state_connection:[1,1,1,""]},"nepi.resources.ns3.classes.lte_enb_net_device":{NS3LteEnbNetDevice:[11,3,1,""]},"nepi.resources.omf.channel":{OMFChannel:[4,3,1,""]},"nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation":{clone_command:[2,1,1,""],netns_src:[2,4,1,""],socket_name:[2,4,1,""],python_unshare_repo:[2,4,1,""],do_start:[2,1,1,""],valid_connection:[2,1,1,""],replace_paths:[2,1,1,""],python_unshare_version:[2,4,1,""],do_stop:[2,1,1,""],upload_sources:[2,1,1,""],do_release:[2,1,1,""],python_unshare_src:[2,4,1,""],wait_remote_socket:[2,1,1,""],python_passfd_version:[2,4,1,""],do_deploy:[2,1,1,""],netns_version:[2,4,1,""],remote_socket:[2,4,1,""],netns_repo:[2,4,1,""],upload_extra_sources:[2,1,1,""],python_passfd_src:[2,4,1,""],upload_start_command:[2,1,1,""],python_passfd_repo:[2,4,1,""]},"nepi.execution.resource.ResourceFactory":{create:[10,5,1,""],register_type:[10,5,1,""],resource_types:[10,5,1,""],get_resource_type:[10,5,1,""]},"nepi.util.timefuncs":{stabsformat:[16,2,1,""],compute_delay_ms:[16,2,1,""],tdiff:[16,2,1,""],tnow:[16,2,1,""],tsformat:[16,2,1,""],stformat:[16,2,1,""],tdiffsec:[16,2,1,""]},"nepi.execution.attribute.Types":{Integer:[10,4,1,""],Double:[10,4,1,""],Bool:[10,4,1,""],String:[10,4,1,""],Enumerate:[10,4,1,""]},"nepi.resources.omf.messages_5_4.MessageHandler":{enroll_function:[4,1,1,""],configure_function:[4,1,1,""],exit_function:[4,1,1,""],alias_function:[4,1,1,""],execute_function:[4,1,1,""],stdin_function:[4,1,1,""],log_function:[4,1,1,""],noop_function:[4,1,1,""],newexp_function:[4,1,1,""]},"nepi.resources.omf.messages_6":{MessageHandler:[4,3,1,""]},"nepi.resources.ns3.ns3queue.NS3BaseQueue":{device:[6,4,1,""],node:[6,4,1,""]},"nepi.resources.linux.gretunnel":{LinuxGRETunnel:[1,3,1,""]},"nepi.resources.ns3.classes.ocb_wifi_mac":{NS3OcbWifiMac:[11,3,1,""]},"nepi.execution.ec.FailureManager":{ec:[10,4,1,""],abort:[10,4,1,""],eval_failure:[10,1,1,""],set_ec_failure:[10,1,1,""],set_ec:[10,1,1,""]},"nepi.resources.omf.omf_api_factory.OMFAPIFactory":{lock:[4,4,1,""],create_api:[4,5,1,""],release_api:[4,5,1,""],get_api:[4,5,1,""]},"nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager":{device:[6,4,1,""],node:[6,4,1,""]},"nepi.resources.ns3.ns3wifiphy":{NS3BaseWifiPhy:[6,3,1,""]},"nepi.resources.ns3.ns3arpl3protocol.NS3BaseArpL3Protocol":{node:[6,4,1,""]},"nepi.resources.planetlab.openvswitch.ovsport":{PlanetlabOVSPort:[19,3,1,""]},"nepi.data.processing.ccn":{parser:[3,0,0,"-"]},"nepi.resources.ns3.classes.log_distance_propagation_loss_model":{NS3LogDistancePropagationLossModel:[11,3,1,""]},"nepi.resources.ns3.ns3fdnetdevice.NS3BaseFdNetDevice":{recv_fd:[6,1,1,""]},"nepi.resources.ns3.classes.udp_trace_client":{NS3UdpTraceClient:[11,3,1,""]},"nepi.resources.ns3.ns3wifiremotestationmanager":{NS3BaseWifiRemoteStationManager:[6,3,1,""]},"nepi.resources.ns3.classes.random_direction2d_mobility_model":{NS3RandomDirection2dMobilityModel:[11,3,1,""]},"nepi.resources.ns3.ns3wifichannel.NS3BaseWifiChannel":{phys:[6,4,1,""],simulation:[6,4,1,""]},"nepi.resources.ns3.classes.constant_velocity_mobility_model":{NS3ConstantVelocityMobilityModel:[11,3,1,""]},"nepi.resources.ns3.classes.three_log_distance_propagation_loss_model":{NS3ThreeLogDistancePropagationLossModel:[11,3,1,""]},"nepi.resources.ns3.classes":{constant_rate_wifi_manager:[11,0,0,"-"],sta_wifi_mac:[11,0,0,"-"],waypoint_mobility_model:[11,0,0,"-"],ocb_wifi_mac:[11,0,0,"-"],dsrdsr_routing:[11,0,0,"-"],hybrid_buildings_propagation_loss_model:[11,0,0,"-"],packet_sink:[11,0,0,"-"],loopback_net_device:[11,0,0,"-"],itu_r1411los_propagation_loss_model:[11,0,0,"-"],nist_error_rate_model:[11,0,0,"-"],yans_wifi_channel:[11,0,0,"-"],point_to_point_channel:[11,0,0,"-"],random_direction2d_mobility_model:[11,0,0,"-"],lr_wpan_net_device:[11,0,0,"-"],udp_trace_client:[11,0,0,"-"],list_error_model:[11,0,0,"-"],bridge_net_device:[11,0,0,"-"],jakes_propagation_loss_model:[11,0,0,"-"],rraa_wifi_manager:[11,0,0,"-"],receive_list_error_model:[11,0,0,"-"],virtual_net_device:[11,0,0,"-"],minstrel_wifi_manager:[11,0,0,"-"],multi_model_spectrum_channel:[11,0,0,"-"],itu_r1411nlos_over_rooftop_propagation_loss_model:[11,0,0,"-"],lte_enb_net_device:[11,0,0,"-"],point_to_point_remote_channel:[11,0,0,"-"],binary_error_sixlow_model:[11,0,0,"-"],error_channel:[11,0,0,"-"],aloha_noack_net_device:[11,0,0,"-"],udp_l4protocol:[11,0,0,"-"],amrr_wifi_manager:[11,0,0,"-"],ideal_wifi_manager:[11,0,0,"-"],rate_error_model:[11,0,0,"-"],kun2600mhz_propagation_loss_model:[11,0,0,"-"],icmpv6l4protocol:[11,0,0,"-"],csma_net_device:[11,0,0,"-"],udp_echo_client:[11,0,0,"-"],constant_speed_propagation_delay_model:[11,0,0,"-"],drop_tail_queue:[11,0,0,"-"],random_propagation_delay_model:[11,0,0,"-"],ping6:[11,0,0,"-"],constant_position_mobility_model:[11,0,0,"-"],onoe_wifi_manager:[11,0,0,"-"],okumura_hata_propagation_loss_model:[11,0,0,"-"],bulk_send_application:[11,0,0,"-"],lte_simple_net_device:[11,0,0,"-"],yans_error_rate_model:[11,0,0,"-"],non_communicating_net_device:[11,0,0,"-"],red_queue:[11,0,0,"-"],mesh_wifi_interface_mac:[11,0,0,"-"],error_net_device:[11,0,0,"-"],aarfcd_wifi_manager:[11,0,0,"-"],v4ping:[11,0,0,"-"],binary_error_model:[11,0,0,"-"],emu_net_device:[11,0,0,"-"],hierarchical_mobility_model:[11,0,0,"-"],fd_net_device:[11,0,0,"-"],constant_acceleration_mobility_model:[11,0,0,"-"],gauss_markov_mobility_model:[11,0,0,"-"],ipv4l3protocol:[11,0,0,"-"],constant_velocity_mobility_model:[11,0,0,"-"],ap_wifi_mac:[11,0,0,"-"],simple_net_device:[11,0,0,"-"],csma_channel:[11,0,0,"-"],icmpv4l4protocol:[11,0,0,"-"],wifi_net_device:[11,0,0,"-"],oh_buildings_propagation_loss_model:[11,0,0,"-"],range_propagation_loss_model:[11,0,0,"-"],lte_ue_net_device:[11,0,0,"-"],yans_wifi_phy:[11,0,0,"-"],single_model_spectrum_channel:[11,0,0,"-"],mesh_point_device:[11,0,0,"-"],simple_channel:[11,0,0,"-"],arf_wifi_manager:[11,0,0,"-"],three_log_distance_propagation_loss_model:[11,0,0,"-"],friis_propagation_loss_model:[11,0,0,"-"],aarf_wifi_manager:[11,0,0,"-"],tap_bridge:[11,0,0,"-"],random_propagation_loss_model:[11,0,0,"-"],random_walk2d_mobility_model:[11,0,0,"-"],radvd:[11,0,0,"-"],six_low_pan_net_device:[11,0,0,"-"],on_off_application:[11,0,0,"-"],arp_l3protocol:[11,0,0,"-"],fixed_rss_loss_model:[11,0,0,"-"],adhoc_wifi_mac:[11,0,0,"-"],base_station_net_device:[11,0,0,"-"],log_distance_propagation_loss_model:[11,0,0,"-"],udp_echo_server:[11,0,0,"-"],udp_client:[11,0,0,"-"],steady_state_random_waypoint_mobility_model:[11,0,0,"-"],point_to_point_net_device:[11,0,0,"-"],tcp_l4protocol:[11,0,0,"-"],random_waypoint_mobility_model:[11,0,0,"-"],nakagami_propagation_loss_model:[11,0,0,"-"],burst_error_model:[11,0,0,"-"],subscriber_station_net_device:[11,0,0,"-"],error_channel_sixlow:[11,0,0,"-"],node:[11,0,0,"-"],cost231propagation_loss_model:[11,0,0,"-"],two_ray_ground_propagation_loss_model:[11,0,0,"-"],cara_wifi_manager:[11,0,0,"-"],matrix_propagation_loss_model:[11,0,0,"-"],udp_server:[11,0,0,"-"],bridge_channel:[11,0,0,"-"],uan_channel:[11,0,0,"-"]},"nepi.resources.planetlab.openvswitch.ovs":{PlanetlabOVSSwitch:[19,3,1,""]},"nepi.resources.netns.netnsapplication.NetNSApplication":{node:[20,4,1,""],state:[20,4,1,""],emulation:[20,4,1,""],do_start:[20,1,1,""]},"nepi.resources.ns3.ns3dceapplication":{NS3BaseDceApplication:[6,3,1,""]},"nepi.resources.linux.ccn.ccnping.LinuxCCNPing":{ccnpingserver:[0,4,1,""],valid_connection:[0,1,1,""],do_start:[0,1,1,""]},"nepi.resources.linux.netns":{netnsclient:[2,0,0,"-"],netnsemulation:[2,0,0,"-"]},"nepi.resources.ns3.classes.on_off_application":{NS3OnOffApplication:[11,3,1,""]},"nepi.resources.omf.omf5_api.OMF5API":{execute:[4,1,1,""],disconnect:[4,1,1,""],configure:[4,1,1,""],enroll_host:[4,1,1,""],exit:[4,1,1,""],send_stdin:[4,1,1,""],release:[4,1,1,""],"delete":[4,1,1,""]},"nepi.resources.ns3.classes.bridge_channel":{NS3BridgeChannel:[11,3,1,""]},"nepi.util.parallel.ParallelRun":{initialize_workers:[16,1,1,""],join:[16,1,1,""],sync:[16,1,1,""],start:[16,1,1,""],put_nowait:[16,1,1,""],put:[16,1,1,""],destroy:[16,1,1,""],empty:[16,1,1,""]},"nepi.resources.ns3.ns3icmpv4l4protocol.NS3BaseIcmpv4L4Protocol":{node:[6,4,1,""]},"nepi.resources.linux.ns3.ns3client":{LinuxNS3Client:[8,3,1,""]},"nepi.resources.ns3.classes.error_channel":{NS3ErrorChannel:[11,3,1,""]},"nepi.resources.ns3.ns3dcehelper":{NS3DceHelper:[6,3,1,""]},"nepi.resources.linux.ns3.ns3simulation":{LinuxNS3Simulation:[8,3,1,""]},"nepi.util.sfaapi":{SFAAPI:[16,3,1,""],SFAAPIFactory:[16,3,1,""]},"nepi.resources.ns3.classes.udp_server":{NS3UdpServer:[11,3,1,""]},"nepi.util.sfaapi.SFAAPIFactory":{make_key:[16,5,1,""],get_api:[16,5,1,""]},"nepi.resources.omf.omf6_parser":{OMF6Parser:[4,3,1,""]},"nepi.resources.netns.netnswrapper":{NetNSWrapper:[20,3,1,""]},"nepi.resources.ns3.classes.wifi_net_device":{NS3WifiNetDevice:[11,3,1,""]},"nepi.resources.all":{collector:[13,0,0,"-"]},"nepi.resources.ns3.classes.ideal_wifi_manager":{NS3IdealWifiManager:[11,3,1,""]},"nepi.resources.linux.netns.netnsemulation":{LinuxNetNSEmulation:[2,3,1,""]},"nepi.resources.ns3.classes.waypoint_mobility_model":{NS3WaypointMobilityModel:[11,3,1,""]},"nepi.util.sfarspec_proc":{SfaRSpecProcessing:[16,3,1,""]},"nepi.resources.omf.omf5_api":{OMF5API:[4,3,1,""]},"nepi.execution.trace":{TraceAttr:[10,3,1,""],Trace:[10,3,1,""]},"nepi.resources.ns3.classes.fixed_rss_loss_model":{NS3FixedRssLossModel:[11,3,1,""]},"nepi.resources.ns3.ns3wrapper":{NS3Wrapper:[6,3,1,""],load_ns3_module:[6,2,1,""],load_ns3_libraries:[6,2,1,""]},"nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel":{establish_connection:[8,1,1,""],wait_file:[8,1,1,""],establish:[8,1,1,""],endpoint_node:[8,1,1,""],wait_local_port:[8,1,1,""],verify:[8,1,1,""],run_home:[8,1,1,""],endpoint1:[8,4,1,""],endpoint2:[8,4,1,""],pi:[8,4,1,""],check_state_connection:[8,1,1,""],app_home:[8,1,1,""],upload_sources:[8,1,1,""],verify_connection:[8,1,1,""],log_message:[8,1,1,""],wait_result:[8,1,1,""],initiate_connection:[8,1,1,""],initiate:[8,1,1,""],endpoint_mkdir:[8,1,1,""],node1:[8,4,1,""],node2:[8,4,1,""],terminate_connection:[8,1,1,""],get_endpoints:[8,1,1,""]},"nepi.resources.ns3.ns3client":{NS3Client:[6,3,1,""]},"nepi.resources.ns3.classes.gauss_markov_mobility_model":{NS3GaussMarkovMobilityModel:[11,3,1,""]},"nepi.resources.linux.ccn.ccnpingserver.LinuxCCNPingServer":{do_deploy:[0,1,1,""],valid_connection:[0,1,1,""]},"nepi.resources.ns3.classes.minstrel_wifi_manager":{NS3MinstrelWifiManager:[11,3,1,""]},"nepi.util.execfuncs":{lcopy:[16,2,1,""],lkill:[16,2,1,""],lstatus:[16,2,1,""],lspawn:[16,2,1,""],lgetpid:[16,2,1,""],lexec:[16,2,1,""]},"nepi.resources.ns3.ns3application.NS3BaseApplication":{node:[6,4,1,""],do_stop:[6,1,1,""],state:[6,4,1,""],do_start:[6,1,1,""]},"nepi.execution.resource.ResourceManager":{do_fail:[10,1,1,""],do_configure:[10,1,1,""],set:[10,1,1,""],register_connection:[10,1,1,""],trace_enabled:[10,1,1,""],get_global:[10,5,1,""],do_connect:[10,1,1,""],do_release:[10,1,1,""],discover:[10,1,1,""],ec:[10,4,1,""],deploy_with_conditions:[10,1,1,""],do_discover:[10,1,1,""],set_global:[10,5,1,""],set_state:[10,1,1,""],set_stopped:[10,1,1,""],do_start:[10,1,1,""],is_rm_instance:[10,1,1,""],guid:[10,4,1,""],set_failed:[10,1,1,""],has_flag:[10,1,1,""],do_reserve:[10,1,1,""],stop_with_conditions:[10,1,1,""],has_changed:[10,1,1,""],valid_connection:[10,1,1,""],failed_time:[10,4,1,""],get:[10,1,1,""],unregister_connection:[10,1,1,""],discover_time:[10,4,1,""],set_state_time:[10,1,1,""],start:[10,1,1,""],state:[10,4,1,""],reserved_time:[10,4,1,""],has_attribute:[10,1,1,""],set_started:[10,1,1,""],set_provisioned:[10,1,1,""],get_rtype:[10,5,1,""],enable_trace:[10,1,1,""],set_discovered:[10,1,1,""],configure:[10,1,1,""],trace:[10,1,1,""],deploy:[10,1,1,""],stop:[10,1,1,""],start_time:[10,4,1,""],do_provision:[10,1,1,""],get_attribute:[10,5,1,""],stop_time:[10,4,1,""],connections:[10,4,1,""],set_with_conditions:[10,1,1,""],reschedule_delay:[10,4,1,""],do_deploy:[10,1,1,""],get_traces:[10,5,1,""],get_platform:[10,5,1,""],do_stop:[10,1,1,""],log_message:[10,1,1,""],register_condition:[10,1,1,""],provision:[10,1,1,""],provision_time:[10,4,1,""],unregister_condition:[10,1,1,""],get_connected:[10,1,1,""],start_with_conditions:[10,1,1,""],ready_time:[10,4,1,""],conditions:[10,4,1,""],set_reserved:[10,1,1,""],set_released:[10,1,1,""],release_time:[10,4,1,""],do_disconnect:[10,1,1,""],get_help:[10,5,1,""],release:[10,1,1,""],fail:[10,1,1,""],set_ready:[10,1,1,""],get_attributes:[10,5,1,""],reserve:[10,1,1,""]},"nepi.util.rmatcher":{find_boxes:[16,2,1,""],match_tags:[16,2,1,""]},"nepi.resources.linux.ns3.ccn.ns3ccnddceapplication":{LinuxNS3DceCCND:[14,3,1,""]},"nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger":{format_kwargs:[6,1,1,""],dump_factory:[6,1,1,""],dump_invoke:[6,1,1,""],dump_shutdown:[6,1,1,""],dump_stop:[6,1,1,""],dump_to_script:[6,1,1,""],enabled:[6,4,1,""],dump_create:[6,1,1,""],format_value:[6,1,1,""],dump_header:[6,1,1,""],format_args:[6,1,1,""],dump_start:[6,1,1,""],script_path:[6,4,1,""],dump_set:[6,1,1,""],dump_get:[6,1,1,""]},"nepi.resources.ns3.ns3propagationdelaymodel":{NS3BasePropagationDelayModel:[6,3,1,""]},"nepi.resources.ns3.ns3mobilitymodel":{NS3BaseMobilityModel:[6,3,1,""]},"nepi.resources.ns3.classes.base_station_net_device":{NS3BaseStationNetDevice:[11,3,1,""]},"nepi.resources.ns3.ns3errorratemodel":{NS3BaseErrorRateModel:[6,3,1,""]},"nepi.resources":{all:[13,0,0,"-"],omf:[4,0,0,"-"],planetlab:[9,0,0,"-"],linux:[1,0,0,"-"],netns:[20,0,0,"-"],ns3:[6,0,0,"-"]},nepi:{util:[16,0,0,"-"],execution:[10,0,0,"-"],data:[18,0,0,"-"],resources:[21,0,0,"-"]},"nepi.resources.ns3.classes.ipv4l3protocol":{NS3Ipv4L3Protocol:[11,3,1,""]},"nepi.resources.ns3.classes.error_channel_sixlow":{NS3ErrorChannelSixlow:[11,3,1,""]},"nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model":{NS3SteadyStateRandomWaypointMobilityModel:[11,3,1,""]},"nepi.resources.linux":{node:[1,0,0,"-"],tap:[1,0,0,"-"],application:[1,0,0,"-"],mtr:[1,0,0,"-"],route:[1,0,0,"-"],ping:[1,0,0,"-"],traceroute:[1,0,0,"-"],udptunnel:[1,0,0,"-"],ccn:[0,0,0,"-"],tunnel:[1,0,0,"-"],nping:[1,0,0,"-"],rpmfuncs:[1,0,0,"-"],tun:[1,0,0,"-"],gretunnel:[1,0,0,"-"],"interface":[1,0,0,"-"],netns:[2,0,0,"-"],debfuncs:[1,0,0,"-"],ns3:[8,0,0,"-"],tcpdump:[1,0,0,"-"],udptest:[1,0,0,"-"],channel:[1,0,0,"-"]},"nepi.resources.ns3.classes.binary_error_model":{NS3BinaryErrorModel:[11,3,1,""]},"nepi.resources.planetlab.openvswitch":{ovs:[19,0,0,"-"],ovsport:[19,0,0,"-"]},"nepi.resources.omf":{node:[4,0,0,"-"],omf_client:[4,0,0,"-"],messages_6:[4,0,0,"-"],omf5_api:[4,0,0,"-"],omf_api_factory:[4,0,0,"-"],omf6_parser:[4,0,0,"-"],omf_resource:[4,0,0,"-"],application:[4,0,0,"-"],messages_5_4:[4,0,0,"-"],"interface":[4,0,0,"-"],omf6_api:[4,0,0,"-"],wilabt_node:[4,0,0,"-"],channel:[4,0,0,"-"]},"nepi.util.guid.GuidGenerator":{next:[16,1,1,""]},"nepi.resources.ns3.ns3simulation.NS3Simulation":{ns3_set:[6,1,1,""],invoke:[6,1,1,""],create:[6,1,1,""],stop:[6,1,1,""],factory:[6,1,1,""],start:[6,1,1,""],client:[6,4,1,""],shutdown:[6,1,1,""],flush:[6,1,1,""],ns3_get:[6,1,1,""]},"nepi.resources.ns3.classes.mesh_point_device":{NS3MeshPointDevice:[11,3,1,""]},"nepi.resources.linux.tcpdump":{LinuxTcpdump:[1,3,1,""]},"nepi.util.parallel":{WorkerThread:[16,3,1,""],ParallelRun:[16,3,1,""]},"nepi.util.plotter":{PFormats:[16,3,1,""],ECPlotter:[16,3,1,""]},"nepi.resources.planetlab.tap.PlanetlabTap":{node:[9,4,1,""],valid_connection:[9,1,1,""],vif_name_file:[9,4,1,""],gre_connect:[9,1,1,""],upload_start_command:[9,1,1,""],wait_vif_name:[9,1,1,""],upload_sources:[9,1,1,""]},"nepi.resources.linux.ccn.ccnpoke.LinuxCCNPoke":{do_deploy:[0,1,1,""],valid_connection:[0,1,1,""]},"nepi.execution.ec.ECState":{TERMINATED:[10,4,1,""],RUNNING:[10,4,1,""],RELEASED:[10,4,1,""],FAILED:[10,4,1,""]},"nepi.resources.ns3.classes.tap_bridge":{NS3TapBridge:[11,3,1,""]},"nepi.resources.linux.gretunnel.LinuxGRETunnel":{valid_connection:[1,1,1,""],verify_connection:[1,1,1,""],initiate_connection:[1,1,1,""],establish_connection:[1,1,1,""],log_message:[1,1,1,""],terminate_connection:[1,1,1,""],get_endpoints:[1,1,1,""],check_state_connection:[1,1,1,""]},"nepi.data":{processing:[15,0,0,"-"]},"nepi.resources.planetlab.sfa_node.PlanetlabSfaNode":{sfaapi:[9,4,1,""],do_release:[9,1,1,""],valid_connection:[9,1,1,""],do_provision:[9,1,1,""],do_discover:[9,1,1,""],fail_sfaapi:[9,1,1,""],fail_not_enough_nodes:[9,1,1,""],fail_node_not_alive:[9,1,1,""],fail_discovery:[9,1,1,""],fail_node_not_available:[9,1,1,""]},"nepi.resources.planetlab.tun":{PlanetlabTun:[9,3,1,""]},"nepi.resources.ns3.ns3server.NS3WrapperMessage":{SET:[6,4,1,""],INVOKE:[6,4,1,""],GET:[6,4,1,""],CREATE:[6,4,1,""],STOP:[6,4,1,""],FACTORY:[6,4,1,""],START:[6,4,1,""],SHUTDOWN:[6,4,1,""],FLUSH:[6,4,1,""]},"nepi.resources.ns3.ns3netdevice":{NS3BaseNetDevice:[6,3,1,""]},"nepi.resources.planetlab.vroute.PlanetlabVroute":{node:[9,4,1,""],tap:[9,4,1,""],valid_connection:[9,1,1,""],do_release:[9,1,1,""],do_deploy:[9,1,1,""],do_start:[9,1,1,""],upload_start_command:[9,1,1,""],do_stop:[9,1,1,""],upload_sources:[9,1,1,""]},"nepi.resources.ns3":{ns3wrapper_debug:[6,0,0,"-"],ns3errorratemodel:[6,0,0,"-"],ns3errormodel:[6,0,0,"-"],ns3wifiphy:[6,0,0,"-"],ns3wifimac:[6,0,0,"-"],ns3arpl3protocol:[6,0,0,"-"],ns3route:[6,0,0,"-"],ns3dceapplication:[6,0,0,"-"],resource_manager_generator:[6,0,0,"-"],ns3icmpv4l4protocol:[6,0,0,"-"],ns3propagationlossmodel:[6,0,0,"-"],ns3simulation:[6,0,0,"-"],ns3pipechanel:[6,0,0,"-"],ns3queue:[6,0,0,"-"],ns3wrapper:[6,0,0,"-"],ns3mobilitymodel:[6,0,0,"-"],ns3propagationdelaymodel:[6,0,0,"-"],ns3fdnetdevice:[6,0,0,"-"],ns3channel:[6,0,0,"-"],ns3ccndceapplication:[6,0,0,"-"],ns3wifiremotestationmanager:[6,0,0,"-"],ns3client:[6,0,0,"-"],ns3dcehelper:[6,0,0,"-"],ns3wifichannel:[6,0,0,"-"],ns3node:[6,0,0,"-"],ns3wifinetdevice:[6,0,0,"-"],ns3ipv4l3protocol:[6,0,0,"-"],ns3server:[6,0,0,"-"],ns3netdevice:[6,0,0,"-"],ns3base:[6,0,0,"-"],classes:[11,0,0,"-"],ns3application:[6,0,0,"-"]},"nepi.resources.ns3.ns3wifiphy.NS3BaseWifiPhy":{device:[6,4,1,""],node:[6,4,1,""],channel:[6,4,1,""]},"nepi.resources.linux.nping.LinuxNPing":{do_deploy:[1,1,1,""],valid_connection:[1,1,1,""]},"nepi.execution.scheduler.TaskStatus":{NEW:[10,4,1,""],DONE:[10,4,1,""],ERROR:[10,4,1,""]},"nepi.resources.linux.ns3.ns3pingdceapplication":{LinuxDcePing:[8,3,1,""]},"nepi.util.serializer.SFormats":{XML:[16,4,1,""]},"nepi.resources.ns3.ns3simulation":{NS3Simulation:[6,3,1,""]},"nepi.resources.ns3.classes.nist_error_rate_model":{NS3NistErrorRateModel:[11,3,1,""]},"nepi.resources.netns":{netnswrapper:[20,0,0,"-"],netnsbase:[20,0,0,"-"],netnsserver:[20,0,0,"-"],netnsipv4address:[20,0,0,"-"],netnswrapper_debug:[20,0,0,"-"],netnsapplication:[20,0,0,"-"],netnsnodeinterface:[20,0,0,"-"],netnsinterface:[20,0,0,"-"],netnsemulation:[20,0,0,"-"],netnsnode:[20,0,0,"-"],netnsroute:[20,0,0,"-"],netnsclient:[20,0,0,"-"],netnsswitch:[20,0,0,"-"]},"nepi.util.parsers.xml_parser.ECXMLParser":{from_xml:[23,1,1,""],to_xml:[23,1,1,""]},"nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model":{NS3Kun2600MhzPropagationLossModel:[11,3,1,""]},"nepi.resources.netns.netnsswitch.NetNSSwitch":{"interface":[20,4,1,""],node:[20,4,1,""],emulation:[20,4,1,""]},"nepi.resources.ns3.classes.constant_speed_propagation_delay_model":{NS3ConstantSpeedPropagationDelayModel:[11,3,1,""]},"nepi.resources.ns3.ns3errormodel":{NS3BaseErrorModel:[6,3,1,""]},"nepi.resources.linux.node.OSType":{FEDORA_12:[1,4,1,""],FEDORA_14:[1,4,1,""],FEDORA:[1,4,1,""],FEDORA_8:[1,4,1,""],UBUNTU:[1,4,1,""],DEBIAN:[1,4,1,""]},"nepi.data.processing.ccn.parser":{annotate_cn_graph:[3,2,1,""],process_content_history_logs:[3,2,1,""],process_content_history:[3,2,1,""],ccn_consumers:[3,2,1,""],is_control:[3,2,1,""],ccn_producers:[3,2,1,""],annotate_cn_node:[3,2,1,""],parse_file:[3,2,1,""],load_content_history:[3,2,1,""],dump_content_history:[3,2,1,""]},"nepi.resources.planetlab.ns3":{fdudptunnel:[7,0,0,"-"],tuntapfdlink:[7,0,0,"-"]},"nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice":{node:[6,4,1,""],queue:[6,4,1,""],ascii_helper_uuid:[6,4,1,""],channel:[6,4,1,""],device_helper_uuid:[6,4,1,""]},"nepi.resources.ns3.ns3wrapper.NS3Wrapper":{is_started:[6,4,1,""],debuger:[6,4,1,""],start:[6,1,1,""],invoke:[6,1,1,""],get:[6,1,1,""],replace_kwargs:[6,1,1,""],create:[6,1,1,""],stop:[6,1,1,""],factory:[6,1,1,""],is_running:[6,4,1,""],ns3:[6,4,1,""],get_object:[6,1,1,""],set:[6,1,1,""],make_uuid:[6,1,1,""],shutdown:[6,1,1,""],replace_args:[6,1,1,""],logger:[6,4,1,""],allowed_types:[6,4,1,""],is_finished:[6,4,1,""]},"nepi.resources.planetlab.node.PlanetlabNode":{plapi:[9,4,1,""],do_release:[9,1,1,""],valid_connection:[9,1,1,""],lock:[9,4,1,""],do_provision:[9,1,1,""],do_discover:[9,1,1,""],fail_plapi:[9,1,1,""],fail_not_enough_nodes:[9,1,1,""],fail_node_not_alive:[9,1,1,""],fail_discovery:[9,1,1,""],fail_node_not_available:[9,1,1,""]},"nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink":{node:[8,4,1,""],tap:[8,4,1,""],fdnetdevice:[8,4,1,""],fdnode:[8,4,1,""],upload_start_command:[8,1,1,""],do_deploy:[8,1,1,""],do_start:[8,1,1,""],tapnode:[8,4,1,""],upload_sources:[8,1,1,""]},"nepi.resources.ns3.classes.friis_propagation_loss_model":{NS3FriisPropagationLossModel:[11,3,1,""]},"nepi.resources.ns3.ns3base.NS3Base":{node:[6,4,1,""],set:[6,1,1,""],uuid:[6,4,1,""],trace:[6,1,1,""],get:[6,1,1,""],do_provision:[6,1,1,""],state:[6,4,1,""],simulation:[6,4,1,""],do_deploy:[6,1,1,""],connected:[6,4,1,""],do_start:[6,1,1,""],do_stop:[6,1,1,""]},"nepi.resources.linux.udptunnel":{LinuxUdpTunnel:[1,3,1,""]},"nepi.resources.ns3.classes.jakes_propagation_loss_model":{NS3JakesPropagationLossModel:[11,3,1,""]},"nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication":{LinuxNS3DceFIBEntry:[14,3,1,""]},"nepi.resources.ns3.classes.sta_wifi_mac":{NS3StaWifiMac:[11,3,1,""]},"nepi.resources.linux.ns3":{tuntapfdlink:[8,0,0,"-"],fdudptunnel:[8,0,0,"-"],ns3simulation:[8,0,0,"-"],ccn:[14,0,0,"-"],ns3client:[8,0,0,"-"],ns3pingdceapplication:[8,0,0,"-"],ns3dceapplication:[8,0,0,"-"]},"nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication":{LinuxNS3DceCCNPoke:[14,3,1,""]},"nepi.resources.ns3.classes.single_model_spectrum_channel":{NS3SingleModelSpectrumChannel:[11,3,1,""]},"nepi.resources.ns3.classes.lte_ue_net_device":{NS3LteUeNetDevice:[11,3,1,""]},"nepi.resources.ns3.ns3server":{get_options:[6,2,1,""],run_server:[6,2,1,""],close_socket:[6,2,1,""],recv_msg:[6,2,1,""],open_socket:[6,2,1,""],handle_message:[6,2,1,""],send_reply:[6,2,1,""],NS3WrapperMessage:[6,3,1,""]},"nepi.execution.trace.Trace":{help:[10,4,1,""],name:[10,4,1,""]},"nepi.resources.ns3.ns3ipv4l3protocol.NS3BaseIpv4L3Protocol":{node:[6,4,1,""]},"nepi.resources.linux.node":{OSType:[1,3,1,""],LinuxNode:[1,3,1,""],ExitCode:[1,3,1,""]},"nepi.resources.omf.wilabt_node.WilabtSfaNode":{execute:[4,1,1,""],do_release:[4,1,1,""],valid_connection:[4,1,1,""],do_provision:[4,1,1,""],do_discover:[4,1,1,""],sfaapi:[4,4,1,""],fail_sfaapi:[4,1,1,""],do_deploy:[4,1,1,""],fail_not_enough_nodes:[4,1,1,""],fail_node_not_alive:[4,1,1,""],fail_discovery:[4,1,1,""],fail_node_not_available:[4,1,1,""]},"nepi.resources.linux.ns3.tuntapfdlink":{LinuxTunTapFdLink:[8,3,1,""]},"nepi.resources.ns3.ns3client.NS3Client":{set:[6,1,1,""],invoke:[6,1,1,""],get:[6,1,1,""],create:[6,1,1,""],stop:[6,1,1,""],factory:[6,1,1,""],start:[6,1,1,""],shutdown:[6,1,1,""],flush:[6,1,1,""]},"nepi.resources.omf.omf6_api":{OMF6API:[4,3,1,""]},"nepi.resources.ns3.classes.constant_rate_wifi_manager":{NS3ConstantRateWifiManager:[11,3,1,""]},"nepi.resources.ns3.classes.simple_channel":{NS3SimpleChannel:[11,3,1,""]},"nepi.resources.ns3.classes.emu_net_device":{NS3EmuNetDevice:[11,3,1,""]},"nepi.resources.netns.netnsroute":{NetNSIPv4Route:[20,3,1,""]},"nepi.resources.netns.netnsbase.NetNSBase":{set:[20,1,1,""],uuid:[20,4,1,""],trace:[20,1,1,""],get:[20,1,1,""],do_provision:[20,1,1,""],state:[20,4,1,""],do_deploy:[20,1,1,""],connected:[20,4,1,""],do_start:[20,1,1,""],do_stop:[20,1,1,""]},"nepi.resources.linux.ccn.ccnpingserver":{LinuxCCNPingServer:[0,3,1,""]},"nepi.resources.ns3.ns3dcehelper.NS3DceHelper":{dce_manager_uuid:[6,4,1,""],dce_application_uuid:[6,4,1,""],dce_manager_lock:[6,4,1,""],dce_application_lock:[6,4,1,""]},"nepi.resources.omf.messages_5_4":{MessageHandler:[4,3,1,""]},"nepi.resources.linux.node.LinuxNode":{usr_dir:[1,4,1,""],node_home:[1,4,1,""],do_release:[1,1,1,""],install_packages:[1,1,1,""],find_home:[1,1,1,""],kill:[1,1,1,""],valid_connection:[1,1,1,""],download:[1,1,1,""],wait_pid:[1,1,1,""],nepi_home:[1,4,1,""],clean_processes:[1,1,1,""],bin_dir:[1,4,1,""],format_environment:[1,1,1,""],upload_command:[1,1,1,""],mkdir:[1,1,1,""],home_dir:[1,4,1,""],filter_existing_files:[1,1,1,""],run_home:[1,4,1,""],getpid:[1,1,1,""],get_os:[1,1,1,""],src_dir:[1,4,1,""],exp_dir:[1,4,1,""],localhost:[1,4,1,""],rmdir:[1,1,1,""],status:[1,1,1,""],run:[1,1,1,""],clean_experiment:[1,1,1,""],share_dir:[1,4,1,""],do_provision:[1,1,1,""],use_rpm:[1,4,1,""],wait_run:[1,1,1,""],do_deploy:[1,1,1,""],exp_home:[1,4,1,""],log_message:[1,1,1,""],use_deb:[1,4,1,""],copy:[1,1,1,""],is_alive:[1,1,1,""],clean_home:[1,1,1,""],execute:[1,1,1,""],install_packages_command:[1,1,1,""],lib_dir:[1,4,1,""],upload:[1,1,1,""],check_errors:[1,1,1,""],check_output:[1,1,1,""],remove_packages:[1,1,1,""],exitcode:[1,1,1,""],os:[1,4,1,""],run_and_wait:[1,1,1,""]},"nepi.resources.ns3.classes.yans_wifi_channel":{NS3YansWifiChannel:[11,3,1,""]},"nepi.resources.ns3.classes.binary_error_sixlow_model":{NS3BinaryErrorSixlowModel:[11,3,1,""]},"nepi.resources.omf.omf_resource":{ResourceGateway:[4,3,1,""],OMFResource:[4,3,1,""]},"nepi.resources.netns.netnsbase":{NetNSBase:[20,3,1,""]},"nepi.resources.planetlab.vroute":{PlanetlabVroute:[9,3,1,""]},"nepi.resources.ns3.classes.csma_net_device":{NS3CsmaNetDevice:[11,3,1,""]},"nepi.resources.ns3.ns3wrapper_debug":{NS3WrapperDebuger:[6,3,1,""]},"nepi.resources.linux.ns3.fdudptunnel":{LinuxNs3FdUdpTunnel:[8,3,1,""]},"nepi.resources.ns3.classes.red_queue":{NS3RedQueue:[11,3,1,""]},"nepi.resources.linux.tap":{LinuxTap:[1,3,1,""]},"nepi.resources.ns3.classes.list_error_model":{NS3ListErrorModel:[11,3,1,""]},"nepi.resources.ns3.classes.udp_client":{NS3UdpClient:[11,3,1,""]},"nepi.resources.omf.node":{OMFNode:[4,3,1,""]},"nepi.resources.linux.ccn.ccnd.LinuxCCND":{valid_connection:[0,1,1,""],state:[0,4,1,""],do_deploy:[0,1,1,""],version:[0,4,1,""],do_start:[0,1,1,""],do_stop:[0,1,1,""],upload_start_command:[0,1,1,""],path:[0,4,1,""]},"nepi.resources.linux.interface":{LinuxInterface:[1,3,1,""]},"nepi.resources.ns3.classes.non_communicating_net_device":{NS3NonCommunicatingNetDevice:[11,3,1,""]},"nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model":{NS3ItuR1411LosPropagationLossModel:[11,3,1,""]},"nepi.resources.linux.ccn.ccnping":{LinuxCCNPing:[0,3,1,""]},"nepi.resources.ns3.classes.lr_wpan_net_device":{NS3LrWpanNetDevice:[11,3,1,""]},"nepi.resources.ns3.classes.icmpv6l4protocol":{NS3Icmpv6L4Protocol:[11,3,1,""]},"nepi.resources.ns3.classes.tcp_l4protocol":{NS3TcpL4Protocol:[11,3,1,""]},"nepi.resources.linux.netns.netnsclient":{LinuxNetNSClient:[2,3,1,""]},"nepi.resources.ns3.ns3ipv4l3protocol":{NS3BaseIpv4L3Protocol:[6,3,1,""]},"nepi.resources.ns3.classes.onoe_wifi_manager":{NS3OnoeWifiManager:[11,3,1,""]},"nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model":{NS3TwoRayGroundPropagationLossModel:[11,3,1,""]},"nepi.resources.linux.netns.netnsclient.LinuxNetNSClient":{set:[2,1,1,""],send_msg:[2,1,1,""],invoke:[2,1,1,""],get:[2,1,1,""],create:[2,1,1,""],emulation:[2,4,1,""],shutdown:[2,1,1,""],flush:[2,1,1,""]},"nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation":{ns3_build_location:[8,4,1,""],socket_name:[8,4,1,""],do_release:[8,1,1,""],do_start:[8,1,1,""],ns3_src_location:[8,4,1,""],valid_connection:[8,1,1,""],replace_paths:[8,1,1,""],dce_src_location:[8,4,1,""],enable_dce:[8,4,1,""],state:[8,4,1,""],ns3_repo:[8,4,1,""],do_stop:[8,1,1,""],upload_sources:[8,1,1,""],pygccxml_version:[8,4,1,""],configure:[8,1,1,""],trace:[8,1,1,""],wait_remote_socket:[8,1,1,""],do_deploy:[8,1,1,""],remote_socket:[8,4,1,""],dce_helper:[8,4,1,""],dce_version:[8,4,1,""],dce_repo:[8,4,1,""],upload_extra_sources:[8,1,1,""],upload_start_command:[8,1,1,""]},"nepi.resources.ns3.classes.point_to_point_net_device":{NS3PointToPointNetDevice:[11,3,1,""]},"nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort":{node:[19,4,1,""],ovsswitch:[19,4,1,""],establish_udp_connection:[19,1,1,""],valid_connection:[19,1,1,""],initiate_udp_connection:[19,1,1,""],do_release:[19,1,1,""],do_deploy:[19,1,1,""],port_number:[19,4,1,""],check_status:[19,1,1,""],do_provision:[19,1,1,""],terminate_connection:[19,1,1,""],create_port:[19,1,1,""],verify_connection:[19,1,1,""]},"nepi.resources.linux.udptest":{LinuxUdpTest:[1,3,1,""]},"nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication":{LinuxNS3DceCCNCat:[14,3,1,""]},"nepi.resources.ns3.ns3wifinetdevice":{NS3BaseWifiNetDevice:[6,3,1,""]},"nepi.resources.ns3.ns3route":{NS3Route:[6,3,1,""]},"nepi.resources.ns3.classes.bulk_send_application":{NS3BulkSendApplication:[11,3,1,""]},"nepi.execution":{resource:[10,0,0,"-"],trace:[10,0,0,"-"],tags:[10,0,0,"-"],runner:[10,0,0,"-"],attribute:[10,0,0,"-"],ec:[10,0,0,"-"],scheduler:[10,0,0,"-"]},"nepi.resources.netns.netnsipv4address.NetNSIPv4Address":{"interface":[20,4,1,""],node:[20,4,1,""],emulation:[20,4,1,""]},"nepi.resources.planetlab.ns3.tuntapfdlink.PlanetlabTunTapFdLink":{upload_sources:[7,1,1,""],tap:[7,4,1,""],fdnetdevice:[7,4,1,""]},"nepi.resources.ns3.ns3node":{NS3BaseNode:[6,3,1,""]},"nepi.util.environ":{backticks:[16,2,1,""],execute:[16,2,1,""]},"nepi.util.guid":{GuidGenerator:[16,3,1,""]},"nepi.util.parsers":{xml_parser:[23,0,0,"-"]},"nepi.execution.attribute.Flags":{NoWrite:[10,4,1,""],Reserved:[10,4,1,""],NoRead:[10,4,1,""],Global:[10,4,1,""],Construct:[10,4,1,""],Filter:[10,4,1,""],Design:[10,4,1,""],Credential:[10,4,1,""]},"nepi.resources.omf.omf_api_factory":{OMFAPIFactory:[4,3,1,""]},"nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel":{device:[6,4,1,""]},"nepi.resources.omf.application.OMFApplication":{node:[4,4,1,""],check_deploy:[4,1,1,""],valid_connection:[4,1,1,""],add_set_hook:[4,1,1,""],do_release:[4,1,1,""],do_deploy:[4,1,1,""],check_start:[4,1,1,""],stdin_hook:[4,1,1,""],do_start:[4,1,1,""],check_release:[4,1,1,""],trace:[4,1,1,""],do_stop:[4,1,1,""],exp_id:[4,4,1,""]},"nepi.resources.linux.ccn.ccncat":{LinuxCCNCat:[0,3,1,""]},"nepi.util.sfarspec_proc.SfaRSpecProcessing":{parse_sfa_rspec:[16,1,1,""],build_sfa_rspec:[16,1,1,""],make_dict_rec:[16,1,1,""]},"nepi.resources.netns.netnsnodeinterface":{NetNSNodeInterface:[20,3,1,""]},"nepi.resources.ns3.classes.udp_echo_client":{NS3UdpEchoClient:[11,3,1,""]},"nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch":{node:[19,4,1,""],do_provision:[19,1,1,""],check_sliver_ovs:[19,1,1,""],servers_on:[19,1,1,""],do_release:[19,1,1,""],create_bridge:[19,1,1,""],do_deploy:[19,1,1,""],valid_connection:[19,1,1,""],assign_controller:[19,1,1,""],ovs_status:[19,1,1,""]},"nepi.resources.linux.tunnel":{LinuxTunnel:[1,3,1,""]},"nepi.resources.ns3.classes.point_to_point_channel":{NS3PointToPointChannel:[11,3,1,""]},"nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac":{node:[6,4,1,""],device:[6,4,1,""]},"nepi.resources.ns3.classes.fd_net_device":{NS3FdNetDevice:[11,3,1,""]},"nepi.execution.resource.ResourceState":{PROVISIONED:[10,4,1,""],RESERVED:[10,4,1,""],FAILED:[10,4,1,""],STARTED:[10,4,1,""],DISCOVERED:[10,4,1,""],RELEASED:[10,4,1,""],STOPPED:[10,4,1,""],READY:[10,4,1,""],NEW:[10,4,1,""]},"nepi.resources.omf.omf_resource.ResourceGateway":{TestbedtoGateway:[4,4,1,""],AMtoGateway:[4,4,1,""]},"nepi.resources.ns3.classes.simple_net_device":{NS3SimpleNetDevice:[11,3,1,""]},"nepi.resources.planetlab.tap":{PlanetlabTap:[9,3,1,""]},"nepi.resources.linux.application":{LinuxApplication:[1,3,1,""]},"nepi.util.manifoldapi.MANIFOLDAPI":{get_session_key:[16,1,1,""],get_resource_urn:[16,1,1,""],get_slice_resources:[16,1,1,""],get_resource_info:[16,1,1,""],add_resource_to_slice:[16,1,1,""],api:[16,4,1,""],remove_resource_from_slice:[16,1,1,""]},"nepi.data.processing":{ccn:[3,0,0,"-"],ping:[22,0,0,"-"]},"nepi.resources.ns3.classes.arp_l3protocol":{NS3ArpL3Protocol:[11,3,1,""]},"nepi.resources.ns3.ns3propagationdelaymodel.NS3BasePropagationDelayModel":{channel:[6,4,1,""],simulation:[6,4,1,""]},"nepi.resources.ns3.ns3ccndceapplication":{NS3BaseCCNDceApplication:[6,3,1,""]},"nepi.util.parallel.WorkerThread":{attach:[16,1,1,""],run:[16,1,1,""],QUIT:[16,3,1,""],quit:[16,1,1,""]},"nepi.resources.linux.ccn.ccncat.LinuxCCNCat":{do_deploy:[0,1,1,""],valid_connection:[0,1,1,""]},"nepi.resources.ns3.classes.constant_position_mobility_model":{NS3ConstantPositionMobilityModel:[11,3,1,""]},"nepi.resources.omf.messages_6.MessageHandler":{create_function:[4,1,1,""],request_function:[4,1,1,""],configure_function:[4,1,1,""],release_function:[4,1,1,""]},"nepi.resources.ns3.classes.receive_list_error_model":{NS3ReceiveListErrorModel:[11,3,1,""]},"nepi.execution.ec.ExperimentController":{get_task:[10,1,1,""],load:[10,5,1,""],stop:[10,1,1,""],set:[10,1,1,""],nthreads:[10,4,1,""],run_id:[10,4,1,""],trace_enabled:[10,1,1,""],serialize:[10,1,1,""],discover:[10,1,1,""],failure_level:[10,4,1,""],inform_failure:[10,1,1,""],abort:[10,4,1,""],shutdown:[10,1,1,""],set_global:[10,1,1,""],get_provision_time:[10,1,1,""],register_connection:[10,1,1,""],get_failed_time:[10,1,1,""],get_ready_time:[10,1,1,""],schedule:[10,1,1,""],get_global:[10,1,1,""],start:[10,1,1,""],state:[10,1,1,""],get_discover_time:[10,1,1,""],deploy:[10,1,1,""],persist:[10,4,1,""],local_dir:[10,4,1,""],logger:[10,4,1,""],wait:[10,1,1,""],resources:[10,4,1,""],enable_trace:[10,1,1,""],ecstate:[10,4,1,""],trace:[10,1,1,""],get:[10,1,1,""],remove_resource:[10,1,1,""],get_stop_time:[10,1,1,""],get_release_time:[10,1,1,""],get_attribute:[10,1,1,""],wait_started:[10,1,1,""],register_condition:[10,1,1,""],get_traces:[10,1,1,""],exp_id:[10,4,1,""],set_with_conditions:[10,1,1,""],provision:[10,1,1,""],fm:[10,4,1,""],get_resource:[10,1,1,""],run_dir:[10,4,1,""],filter_resources:[10,1,1,""],wait_released:[10,1,1,""],save:[10,1,1,""],wait_deployed:[10,1,1,""],netgraph:[10,4,1,""],get_resources_by_type:[10,1,1,""],plot:[10,1,1,""],register_resource:[10,1,1,""],exp_dir:[10,4,1,""],get_start_time:[10,1,1,""],release:[10,1,1,""],wait_finished:[10,1,1,""],get_attributes:[10,1,1,""]},"nepi.resources.linux.ping":{LinuxPing:[1,3,1,""]},"nepi.resources.ns3.classes.random_walk2d_mobility_model":{NS3RandomWalk2dMobilityModel:[11,3,1,""]},"nepi.execution.scheduler":{Task:[10,3,1,""],HeapScheduler:[10,3,1,""],TaskStatus:[10,3,1,""]},"nepi.resources.omf.wilabt_node":{WilabtSfaNode:[4,3,1,""]},"nepi.resources.linux.traceroute":{LinuxTraceroute:[1,3,1,""]},"nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel":{channel:[6,4,1,""],simulation:[6,4,1,""]},"nepi.resources.linux.ns3.ns3client.LinuxNS3Client":{set:[8,1,1,""],send_msg:[8,1,1,""],invoke:[8,1,1,""],get:[8,1,1,""],create:[8,1,1,""],stop:[8,1,1,""],factory:[8,1,1,""],simulation:[8,4,1,""],start:[8,1,1,""],shutdown:[8,1,1,""],flush:[8,1,1,""]},"nepi.util.manifoldapi":{MANIFOLDAPIFactory:[16,3,1,""],MANIFOLDAPI:[16,3,1,""]},"nepi.resources.linux.channel.LinuxChannel":{log_message:[1,1,1,""],valid_connection:[1,1,1,""]},"nepi.resources.linux.ccn":{ccnpoke:[0,0,0,"-"],ccnapplication:[0,0,0,"-"],fibentry:[0,0,0,"-"],ccnr:[0,0,0,"-"],ccnpingserver:[0,0,0,"-"],ccncontent:[0,0,0,"-"],ccnd:[0,0,0,"-"],ccnpeek:[0,0,0,"-"],ccncat:[0,0,0,"-"],ccnping:[0,0,0,"-"]},"nepi.resources.ns3.classes.random_propagation_loss_model":{NS3RandomPropagationLossModel:[11,3,1,""]},"nepi.resources.omf.interface.OMFWifiInterface":{node:[4,4,1,""],valid_connection:[4,1,1,""],check_deploy:[4,1,1,""],do_release:[4,1,1,""],configure_iface:[4,1,1,""],do_deploy:[4,1,1,""],configure_ip:[4,1,1,""],configure_on_omf5:[4,1,1,""],configure_on_omf6:[4,1,1,""],check_release:[4,1,1,""],exp_id:[4,4,1,""],channel:[4,4,1,""]},"nepi.resources.ns3.ns3fdnetdevice":{NS3BaseFdNetDevice:[6,3,1,""]},"nepi.resources.ns3.classes.mesh_wifi_interface_mac":{NS3MeshWifiInterfaceMac:[11,3,1,""]},"nepi.resources.ns3.classes.oh_buildings_propagation_loss_model":{NS3OhBuildingsPropagationLossModel:[11,3,1,""]},"nepi.resources.omf.node.OMFNode":{exp_id:[4,4,1,""],do_deploy:[4,1,1,""],do_release:[4,1,1,""],valid_connection:[4,1,1,""]},"nepi.resources.ns3.classes.adhoc_wifi_mac":{NS3AdhocWifiMac:[11,3,1,""]},"nepi.resources.netns.netnswrapper_debug":{NetNSWrapperDebuger:[20,3,1,""]},"nepi.util.netgraph":{NetGraph:[16,3,1,""],TopologyType:[16,3,1,""]},"nepi.execution.ec":{ECState:[10,3,1,""],FailureLevel:[10,3,1,""],FailureManager:[10,3,1,""],ExperimentController:[10,3,1,""]},"nepi.resources.ns3.ns3channel.NS3BaseChannel":{devices:[6,4,1,""],simulation:[6,4,1,""]},"nepi.resources.ns3.classes.aarfcd_wifi_manager":{NS3AarfcdWifiManager:[11,3,1,""]},"nepi.resources.ns3.classes.icmpv4l4protocol":{NS3Icmpv4L4Protocol:[11,3,1,""]},"nepi.resources.omf.omf6_parser.OMF6Parser":{check_mailbox:[4,1,1,""],handle:[4,1,1,""],init_mailbox:[4,1,1,""]},"nepi.resources.linux.ns3.ns3dceapplication":{LinuxNS3DceApplication:[8,3,1,""]},"nepi.resources.ns3.ns3wifimac":{NS3BaseWifiMac:[6,3,1,""]},"nepi.resources.linux.ccn.ccnr":{LinuxCCNR:[0,3,1,""]},"nepi.resources.netns.netnsnode.NetNSNode":{emulation:[20,4,1,""]},"nepi.resources.linux.ccn.ccnd":{LinuxCCND:[0,3,1,""]},"nepi.resources.linux.interface.LinuxInterface":{add_set_hooks:[1,1,1,""],node:[1,4,1,""],do_release:[1,1,1,""],valid_connection:[1,1,1,""],do_provision:[1,1,1,""],do_discover:[1,1,1,""],do_deploy:[1,1,1,""],set_hook_mtu:[1,1,1,""],log_message:[1,1,1,""],set_hook_up:[1,1,1,""],channel:[1,4,1,""],load_configuration:[1,1,1,""]},"nepi.resources.netns.netnsclient":{NetNSClient:[20,3,1,""]},"nepi.resources.ns3.classes.rraa_wifi_manager":{NS3RraaWifiManager:[11,3,1,""]},"nepi.resources.ns3.classes.burst_error_model":{NS3BurstErrorModel:[11,3,1,""]},"nepi.resources.planetlab.node":{PlanetlabNode:[9,3,1,""]},"nepi.resources.ns3.classes.amrr_wifi_manager":{NS3AmrrWifiManager:[11,3,1,""]},"nepi.resources.ns3.classes.rate_error_model":{NS3RateErrorModel:[11,3,1,""]},"nepi.resources.ns3.ns3application":{NS3BaseApplication:[6,3,1,""]},"nepi.util.serializer.ECSerializer":{load:[16,1,1,""],save:[16,1,1,""],serialize:[16,1,1,""]},"nepi.resources.linux.ns3.ccn.ns3ccnddceapplication.LinuxNS3DceCCND":{version:[14,4,1,""]},"nepi.resources.linux.ccn.ccncontent.LinuxCCNContent":{node:[0,4,1,""],valid_connection:[0,1,1,""],ccnr:[0,4,1,""],ccnd:[0,4,1,""],do_deploy:[0,1,1,""],do_start:[0,1,1,""],upload_start_command:[0,1,1,""]},"nepi.resources.ns3.classes.cara_wifi_manager":{NS3CaraWifiManager:[11,3,1,""]},"nepi.resources.ns3.classes.constant_acceleration_mobility_model":{NS3ConstantAccelerationMobilityModel:[11,3,1,""]},"nepi.resources.ns3.classes.yans_error_rate_model":{NS3YansErrorRateModel:[11,3,1,""]},"nepi.resources.linux.ccn.ccnr.LinuxCCNR":{node:[0,4,1,""],valid_connection:[0,1,1,""],ccnd:[0,4,1,""],do_deploy:[0,1,1,""],do_start:[0,1,1,""],upload_start_command:[0,1,1,""]},"nepi.resources.linux.tunnel.LinuxTunnel":{app_home:[1,1,1,""],do_provision:[1,1,1,""],valid_connection:[1,1,1,""],verify_connection:[1,1,1,""],do_stop:[1,1,1,""],initiate_connection:[1,1,1,""],establish_connection:[1,1,1,""],do_deploy:[1,1,1,""],state:[1,4,1,""],run_home:[1,1,1,""],endpoint_mkdir:[1,1,1,""],do_start:[1,1,1,""],log_message:[1,1,1,""],endpoint1:[1,4,1,""],endpoint2:[1,4,1,""],terminate_connection:[1,1,1,""],get_endpoints:[1,1,1,""],check_state_connection:[1,1,1,""]},"nepi.resources.planetlab.plcapi":{PLCAPI:[9,3,1,""],PLCAPIFactory:[9,3,1,""]},"nepi.resources.netns.netnsinterface":{NetNSInterface:[20,3,1,""]},"nepi.util.plotter.ECPlotter":{plot:[16,1,1,""]},"nepi.resources.planetlab.plcapi.PLCAPIFactory":{create_api:[9,5,1,""],get_api:[9,5,1,""]},"nepi.resources.ns3.classes.random_propagation_delay_model":{NS3RandomPropagationDelayModel:[11,3,1,""]},"nepi.resources.ns3.classes.error_net_device":{NS3ErrorNetDevice:[11,3,1,""]},"nepi.util.netgraph.NetGraph":{topo_type:[16,4,1,""],add_node:[16,1,1,""],del_node_annotation:[16,1,1,""],targets:[16,1,1,""],node_annotation:[16,1,1,""],generate_topology:[16,1,1,""],annotate_edge:[16,1,1,""],set_target:[16,1,1,""],node_ip_annotations:[16,1,1,""],is_source:[16,1,1,""],select_target_zero:[16,1,1,""],nodes:[16,1,1,""],is_target:[16,1,1,""],set_source:[16,1,1,""],get_p2p_info:[16,1,1,""],select_random_source:[16,1,1,""],edge_net_annotation:[16,1,1,""],edges:[16,1,1,""],add_edge:[16,1,1,""],assign_p2p_ips:[16,1,1,""],topology:[16,4,1,""],annotate_node:[16,1,1,""],annotate_edge_net:[16,1,1,""],sources:[16,1,1,""],node_annotations:[16,1,1,""],del_edge_annotation:[16,1,1,""],order:[16,4,1,""],edge_annotation:[16,1,1,""],edge_annotations:[16,1,1,""],annotate_node_ip:[16,1,1,""]},"nepi.resources.netns.netnsemulation":{NetNSEmulation:[20,3,1,""]},"nepi.resources.ns3.ns3pipechanel.NS3BasePipeChannel":{node:[6,4,1,""],devices:[6,4,1,""]},"nepi.resources.ns3.classes.random_waypoint_mobility_model":{NS3RandomWaypointMobilityModel:[11,3,1,""]},"nepi.resources.omf.omf_client.OMFClient":{check_mailbox:[4,1,1,""],get:[4,1,1,""],unregister:[4,1,1,""],create:[4,1,1,""],register:[4,1,1,""],publish:[4,1,1,""],subscriptions:[4,1,1,""],purge:[4,1,1,""],subscribe:[4,1,1,""],retract:[4,1,1,""],unsubscribe:[4,1,1,""],ready:[4,4,1,""],nodes:[4,1,1,""],handle_omf_message:[4,1,1,""],start:[4,1,1,""],"delete":[4,1,1,""]},"nepi.util.netgraph.TopologyType":{STAR:[16,4,1,""],LINEAR:[16,4,1,""],LADDER:[16,4,1,""],TREE:[16,4,1,""],ADHOC:[16,4,1,""],MESH:[16,4,1,""]},"nepi.resources.ns3.classes.range_propagation_loss_model":{NS3RangePropagationLossModel:[11,3,1,""]},"nepi.resources.planetlab.sfa_node":{PlanetlabSfaNode:[9,3,1,""]},"nepi.resources.ns3.ns3arpl3protocol":{NS3BaseArpL3Protocol:[6,3,1,""]},"nepi.execution.scheduler.HeapScheduler":{next:[10,1,1,""],pending:[10,4,1,""],remove:[10,1,1,""],schedule:[10,1,1,""]},"nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication":{node:[0,4,1,""],ccnd:[0,4,1,""],do_deploy:[0,1,1,""],valid_connection:[0,1,1,""]},"nepi.resources.ns3.ns3wifichannel":{NS3BaseWifiChannel:[6,3,1,""]},"nepi.resources.linux.nping":{LinuxNPing:[1,3,1,""]},"nepi.resources.linux.ccn.fibentry":{LinuxFIBEntry:[0,3,1,""]},"nepi.execution.attribute.Attribute":{has_changed:[10,4,1,""],has_flag:[10,1,1,""],name:[10,4,1,""],"default":[10,4,1,""],get_value:[10,1,1,""],value:[10,4,1,""],is_valid_value:[10,1,1,""],range:[10,4,1,""],flags:[10,4,1,""],allowed:[10,4,1,""],set_value:[10,1,1,""],type:[10,4,1,""],help:[10,4,1,""]},"nepi.resources.linux.udptest.LinuxUdpTest":{upload_start_command:[1,1,1,""],do_deploy:[1,1,1,""],valid_connection:[1,1,1,""],do_start:[1,1,1,""]},"nepi.resources.linux.ccn.ccnapplication":{LinuxCCNApplication:[0,3,1,""]},"nepi.resources.ns3.classes.point_to_point_remote_channel":{NS3PointToPointRemoteChannel:[11,3,1,""]},"nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication":{LinuxNS3DceCCNPeek:[14,3,1,""]},"nepi.resources.planetlab.ns3.tuntapfdlink":{PlanetlabTunTapFdLink:[7,3,1,""]},"nepi.resources.ns3.resource_manager_generator":{create_ns3_rms:[6,2,1,""],template_traces:[6,2,1,""],select_base_class:[6,2,1,""],template_attributes:[6,2,1,""]},"nepi.util.sfaapi.SFAAPI":{blacklist_resource:[16,1,1,""],reserved:[16,1,1,""],blacklisted:[16,1,1,""],get_resources_hrn:[16,1,1,""],reserve_resource:[16,1,1,""],remove_all_from_slice:[16,1,1,""],get_slice_resources:[16,1,1,""],remove_resource_from_slice:[16,1,1,""],add_resource_to_slice:[16,1,1,""],add_resource_to_slice_batch:[16,1,1,""],release:[16,1,1,""],get_resources_info:[16,1,1,""]},"nepi.resources.ns3.classes.udp_l4protocol":{NS3UdpL4Protocol:[11,3,1,""]},"nepi.resources.netns.netnsemulation.NetNSEmulation":{emu_set:[20,1,1,""],invoke:[20,1,1,""],create:[20,1,1,""],client:[20,4,1,""],shutdown:[20,1,1,""],flush:[20,1,1,""],emu_get:[20,1,1,""]},"nepi.resources.ns3.classes.aloha_noack_net_device":{NS3AlohaNoackNetDevice:[11,3,1,""]},"nepi.resources.linux.mtr":{LinuxMtr:[1,3,1,""]},"nepi.resources.ns3.classes.ping6":{NS3Ping6:[11,3,1,""]},"nepi.execution.ec.FailureLevel":{RM_FAILURE:[10,4,1,""],OK:[10,4,1,""],EC_FAILURE:[10,4,1,""]},"nepi.resources.linux.tun":{LinuxTun:[1,3,1,""]},"nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model":{NS3HybridBuildingsPropagationLossModel:[11,3,1,""]},"nepi.resources.ns3.classes.drop_tail_queue":{NS3DropTailQueue:[11,3,1,""]},"nepi.resources.ns3.ns3propagationlossmodel":{NS3BasePropagationLossModel:[6,3,1,""]},"nepi.resources.ns3.classes.nakagami_propagation_loss_model":{NS3NakagamiPropagationLossModel:[11,3,1,""]},"nepi.execution.resource":{ResourceManager:[10,3,1,""],populate_factory:[10,2,1,""],ResourceAction:[10,3,1,""],find_types:[10,2,1,""],ResourceState:[10,3,1,""],clsinit:[10,2,1,""],ResourceFactory:[10,3,1,""],clsinit_copy:[10,2,1,""],failtrap:[10,2,1,""]},"nepi.execution.attribute":{Attribute:[10,3,1,""],Flags:[10,3,1,""],Types:[10,3,1,""]},"nepi.resources.all.collector.Collector":{do_provision:[13,1,1,""],store_path:[13,4,1,""],do_deploy:[13,1,1,""],do_release:[13,1,1,""],valid_connection:[13,1,1,""]},"nepi.resources.ns3.classes.loopback_net_device":{NS3LoopbackNetDevice:[11,3,1,""]},"nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model":{NS3ItuR1411NlosOverRooftopPropagationLossModel:[11,3,1,""]},"nepi.resources.ns3.ns3pipechanel":{NS3BasePipeChannel:[6,3,1,""]},"nepi.resources.ns3.classes.v4ping":{NS3V4Ping:[11,3,1,""]},"nepi.resources.ns3.classes.lte_simple_net_device":{NS3LteSimpleNetDevice:[11,3,1,""]},"nepi.resources.ns3.classes.dsrdsr_routing":{NS3dsrDsrRouting:[11,3,1,""]},"nepi.resources.ns3.classes.udp_echo_server":{NS3UdpEchoServer:[11,3,1,""]},"nepi.resources.ns3.classes.six_low_pan_net_device":{NS3SixLowPanNetDevice:[11,3,1,""]},"nepi.resources.linux.tap.LinuxTap":{vif_type:[1,4,1,""],IFF_TAP:[1,4,1,""],udp_connect:[1,1,1,""],do_release:[1,1,1,""],wait_file:[1,1,1,""],vif_type_flag:[1,4,1,""],do_start:[1,1,1,""],check_status:[1,1,1,""],establish_udp_connection:[1,1,1,""],valid_connection:[1,1,1,""],initiate_udp_connection:[1,1,1,""],state:[1,4,1,""],do_stop:[1,1,1,""],upload_sources:[1,1,1,""],node:[1,4,1,""],verify_connection:[1,1,1,""],gre_enabled:[1,4,1,""],vif_prefix:[1,4,1,""],gre_connect:[1,1,1,""],do_deploy:[1,1,1,""],sock_name:[1,4,1,""],IFF_TUN:[1,4,1,""],upload_start_command:[1,1,1,""],terminate_connection:[1,1,1,""]},"nepi.resources.linux.ns3.ccn":{ns3ccncatdceapplication:[14,0,0,"-"],ns3fibentrydceapplication:[14,0,0,"-"],ns3ccnpeekdceapplication:[14,0,0,"-"],ns3ccnrdceapplication:[14,0,0,"-"],ns3ccnddceapplication:[14,0,0,"-"],ns3ccndceapplication:[14,0,0,"-"],ns3ccnpokedceapplication:[14,0,0,"-"]},"nepi.resources.ns3.classes.node":{NS3Node:[11,3,1,""]},"nepi.resources.all.collector":{Collector:[13,3,1,""]},"nepi.data.processing.ping":{parser:[22,0,0,"-"]},"nepi.util.logger.Logger":{info:[16,1,1,""],log:[16,1,1,""],warning:[16,1,1,""],error:[16,1,1,""],debug:[16,1,1,""],log_message:[16,1,1,""],logger:[16,4,1,""]},"nepi.resources.linux.ping.LinuxPing":{upload_start_command:[1,1,1,""],do_deploy:[1,1,1,""],valid_connection:[1,1,1,""],do_start:[1,1,1,""]},"nepi.resources.omf.application":{OMFApplication:[4,3,1,""]},"nepi.resources.ns3.ns3queue":{NS3BaseQueue:[6,3,1,""]}},titleterms:{netn:[20,2],all:13,execut:10,ns3wrapper_debug:6,vrout:9,sta_wifi_mac:11,netnswrapper_debug:20,rpmfunc:1,waypoint_mobility_model:11,netnsnod:20,ns3wifiremotestationmanag:6,ccnpeek:0,ocb_wifi_mac:11,omf_api_factori:4,hybrid_buildings_propagation_loss_model:11,netnsswitch:20,packet_sink:11,icmpv6l4protocol:11,itu_r1411los_propagation_loss_model:11,udp_trace_cli:11,ns3propagationlossmodel:6,ns3ccnrdceapplic:14,platform:5,nist_error_rate_model:11,binary_error_sixlow_model:11,ccnpingserv:0,yans_wifi_channel:11,logger:16,point_to_point_channel:11,ns3ccnpeekdceappl:14,ccnping:0,random_direction2d_mobility_model:11,applic:[1,4],omf_client:4,lr_wpan_net_devic:11,ns3fibentrydceappl:14,timefunc:16,rout:1,sshfunc:16,resource_manager_gener:6,ccncontent:0,udptunnel:1,util:[16,23],tap_bridg:11,ns3ccncatdceappl:14,aarfcd_wifi_manag:11,ideal_wifi_manag:11,list_error_model:11,manifoldapi:16,ns3wrapper:6,omf5_api:4,jakes_propagation_loss_model:11,ns3fdnetdevic:6,on_off_appl:11,ns3wifimac:6,red_queu:11,ns3base:6,adhoc_wifi_mac:11,channel:[1,4],ns3ccnddceapplic:14,netnsclient:[20,2],ns3wifinetdevic:6,receive_list_error_model:11,fdudptunnel:[7,8],onoe_wifi_manag:11,ns3netdevic:6,itu_r1411nlos_over_rooftop_propagation_loss_model:11,range_propagation_loss_model:11,point_to_point_remote_channel:11,point_to_point_net_devic:11,csma_net_devic:11,ns3wifiphi:6,arf_wifi_manag:11,fd_net_devic:11,error_channel:11,collector:13,nepi:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],udp_l4protocol:11,ns3pingdceappl:8,ns3node:6,messages_6:4,rate_error_model:11,omf6_api:4,ns3icmpv4l4protocol:6,debfunc:1,content:[0,1,2,3,4,6,7,8,9,10,11,12,13,14,15,16,18,19,20,21,22,23],ns3pipechanel:6,fibentri:0,ns3applic:6,amrr_wifi_manag:11,attribut:10,core:5,ns3propagationdelaymodel:6,cara_wifi_manag:11,omf:4,udp_echo_serv:11,random_propagation_delay_model:11,ping6:11,ovsport:19,omf6_pars:4,constant_position_mobility_model:11,tun:[1,9],ns3client:[8,6],wilabt_nod:4,miscellan:5,okumura_hata_propagation_loss_model:11,ns3rout:6,ns3ccndceapplic:[14,6],messages_5_4:4,netnsipv4address:20,ccnpoke:0,lte_enb_net_devic:11,lte_ue_net_devic:11,netnsrout:20,yans_error_rate_model:11,tunnel:1,six_low_pan_net_devic:11,mesh_wifi_interface_mac:11,rraa_wifi_manag:11,schedul:10,modul:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,21,22,23],bridge_net_devic:11,submodul:[0,6,7,8,1,19,9,2,10,16,23,13,11,3,14,4,22,20],wifi_net_devic:11,statfunc:16,drop_tail_queu:11,linux:[8,0,14,1,2],v4ping:11,tap:[1,9],constant_rate_wifi_manag:11,guid:16,binary_error_model:11,hierarchical_mobility_model:11,ns3queue:6,omf_resourc:4,parallel:16,constant_acceleration_mobility_model:11,gauss_markov_mobility_model:11,ipv4l3protocol:11,process:[3,15,22],netnsappl:20,interfac:[1,4],multi_model_spectrum_channel:11,aarf_wifi_manag:11,ap_wifi_mac:11,ns3dcehelp:6,tcpdump:1,radvd:11,csma_channel:11,icmpv4l4protocol:11,constant_speed_propagation_delay_model:11,minstrel_wifi_manag:11,oh_buildings_propagation_loss_model:11,subscriber_station_net_devic:11,xml_parser:23,nping:1,simple_channel:11,gretunnel:1,ccncat:0,ns3:[7,8,14,11,6],yans_wifi_phi:11,three_log_distance_propagation_loss_model:11,friis_propagation_loss_model:11,base_station_net_devic:11,tuntapfdlink:[7,8],plcapi:9,netnsinterfac:20,netnsemul:[20,2],ns3ipv4l3protocol:6,random_walk2d_mobility_model:11,netnsnodeinterfac:20,bulk_send_appl:11,mtr:1,udp_echo_cli:11,single_model_spectrum_channel:11,plotter:16,ns3ccnpokedceappl:14,arp_l3protocol:11,ccnapplic:0,virtual_net_devic:11,fixed_rss_loss_model:11,ns3errorratemodel:6,netgraph:16,ns3errormodel:6,kun2600mhz_propagation_loss_model:11,runner:10,parser:[3,22,23],indic:5,packag:[0,1,2,3,4,6,7,8,9,10,11,12,13,14,15,16,18,19,20,21,22,23],netnsbas:20,tag:10,tabl:5,ns3arpl3protocol:6,netnsserv:20,serial:16,log_distance_propagation_loss_model:11,tracerout:1,udp_client:11,sfaapi:16,sfa_nod:9,ccnr:0,dsrdsr_rout:11,ns3simul:[8,6],ping:[1,22],error_net_devic:11,random_waypoint_mobility_model:11,ccnd:0,udp_serv:11,nakagami_propagation_loss_model:11,burst_error_model:11,document:[],ns3mobilitymodel:6,error_channel_sixlow:11,node:[11,1,4,9],constant_velocity_mobility_model:11,sfarspec_proc:16,resourc:[0,6,7,8,1,19,9,2,10,13,21,11,14,4,20],trace:10,planetlab:[7,19,9],ns3channel:6,openvswitch:19,tcp_l4protocol:11,cost231propagation_loss_model:11,"class":11,aloha_noack_net_devic:11,mesh_point_devic:11,two_ray_ground_propagation_loss_model:11,rmatcher:16,ns3dceapplic:[8,6],data:[3,15,18,22],netnswrapp:20,matrix_propagation_loss_model:11,steady_state_random_waypoint_mobility_model:11,subpackag:[18,6,8,12,1,9,15,16,21],ns3wifichannel:6,non_communicating_net_devic:11,random_propagation_loss_model:11,ns3server:6,emu_net_devic:11,bridge_channel:11,lte_simple_net_devic:11,loopback_net_devic:11,ccn:[0,14,3],environ:16,execfunc:16,uan_channel:11,udptest:1,simple_net_devic:11}}) \ No newline at end of file diff --git a/doc/sphinx/_layout/modules.rst b/doc/sphinx/_layout/modules.rst new file mode 100644 index 00000000..6486b2cf --- /dev/null +++ b/doc/sphinx/_layout/modules.rst @@ -0,0 +1,7 @@ +nepi +==== + +.. toctree:: + :maxdepth: 4 + + nepi diff --git a/doc/sphinx/_layout/nepi.data.processing.ccn.rst b/doc/sphinx/_layout/nepi.data.processing.ccn.rst new file mode 100644 index 00000000..4b3bb6b2 --- /dev/null +++ b/doc/sphinx/_layout/nepi.data.processing.ccn.rst @@ -0,0 +1,22 @@ +nepi.data.processing.ccn package +================================ + +Submodules +---------- + +nepi.data.processing.ccn.parser module +-------------------------------------- + +.. automodule:: nepi.data.processing.ccn.parser + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.data.processing.ccn + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.data.processing.ping.rst b/doc/sphinx/_layout/nepi.data.processing.ping.rst new file mode 100644 index 00000000..56d3574d --- /dev/null +++ b/doc/sphinx/_layout/nepi.data.processing.ping.rst @@ -0,0 +1,22 @@ +nepi.data.processing.ping package +================================= + +Submodules +---------- + +nepi.data.processing.ping.parser module +--------------------------------------- + +.. automodule:: nepi.data.processing.ping.parser + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.data.processing.ping + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.data.processing.rst b/doc/sphinx/_layout/nepi.data.processing.rst new file mode 100644 index 00000000..6f22a0fa --- /dev/null +++ b/doc/sphinx/_layout/nepi.data.processing.rst @@ -0,0 +1,18 @@ +nepi.data.processing package +============================ + +Subpackages +----------- + +.. toctree:: + + nepi.data.processing.ccn + nepi.data.processing.ping + +Module contents +--------------- + +.. automodule:: nepi.data.processing + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.data.rst b/doc/sphinx/_layout/nepi.data.rst new file mode 100644 index 00000000..2841cdc0 --- /dev/null +++ b/doc/sphinx/_layout/nepi.data.rst @@ -0,0 +1,17 @@ +nepi.data package +================= + +Subpackages +----------- + +.. toctree:: + + nepi.data.processing + +Module contents +--------------- + +.. automodule:: nepi.data + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.execution.rst b/doc/sphinx/_layout/nepi.execution.rst new file mode 100644 index 00000000..c8f46ae0 --- /dev/null +++ b/doc/sphinx/_layout/nepi.execution.rst @@ -0,0 +1,70 @@ +nepi.execution package +====================== + +Submodules +---------- + +nepi.execution.attribute module +------------------------------- + +.. automodule:: nepi.execution.attribute + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.ec module +------------------------ + +.. automodule:: nepi.execution.ec + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.resource module +------------------------------ + +.. automodule:: nepi.execution.resource + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.runner module +---------------------------- + +.. automodule:: nepi.execution.runner + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.scheduler module +------------------------------- + +.. automodule:: nepi.execution.scheduler + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.tags module +-------------------------- + +.. automodule:: nepi.execution.tags + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.trace module +--------------------------- + +.. automodule:: nepi.execution.trace + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.execution + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.all.rst b/doc/sphinx/_layout/nepi.resources.all.rst new file mode 100644 index 00000000..59459003 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.all.rst @@ -0,0 +1,22 @@ +nepi.resources.all package +========================== + +Submodules +---------- + +nepi.resources.all.collector module +----------------------------------- + +.. automodule:: nepi.resources.all.collector + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.all + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.linux.ccn.rst b/doc/sphinx/_layout/nepi.resources.linux.ccn.rst new file mode 100644 index 00000000..871cb33f --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.linux.ccn.rst @@ -0,0 +1,94 @@ +nepi.resources.linux.ccn package +================================ + +Submodules +---------- + +nepi.resources.linux.ccn.ccnapplication module +---------------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccncat module +-------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccncat + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccncontent module +------------------------------------------ + +.. automodule:: nepi.resources.linux.ccn.ccncontent + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnd module +------------------------------------ + +.. automodule:: nepi.resources.linux.ccn.ccnd + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnpeek module +--------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnpeek + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnping module +--------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnpingserver module +--------------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnpingserver + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnpoke module +--------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnpoke + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnr module +------------------------------------ + +.. automodule:: nepi.resources.linux.ccn.ccnr + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.fibentry module +---------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.fibentry + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.ccn + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.linux.netns.rst b/doc/sphinx/_layout/nepi.resources.linux.netns.rst new file mode 100644 index 00000000..a20d9109 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.linux.netns.rst @@ -0,0 +1,30 @@ +nepi.resources.linux.netns package +================================== + +Submodules +---------- + +nepi.resources.linux.netns.netnsclient module +--------------------------------------------- + +.. automodule:: nepi.resources.linux.netns.netnsclient + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.netns.netnsemulation module +------------------------------------------------ + +.. automodule:: nepi.resources.linux.netns.netnsemulation + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.netns + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.linux.ns3.ccn.rst b/doc/sphinx/_layout/nepi.resources.linux.ns3.ccn.rst new file mode 100644 index 00000000..a6e08684 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.linux.ns3.ccn.rst @@ -0,0 +1,70 @@ +nepi.resources.linux.ns3.ccn package +==================================== + +Submodules +---------- + +nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication module +----------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccndceapplication module +-------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccndceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnddceapplication module +--------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnddceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication module +------------------------------------------------------------ + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication module +------------------------------------------------------------ + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication module +--------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication module +------------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.ns3.ccn + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.linux.ns3.rst b/doc/sphinx/_layout/nepi.resources.linux.ns3.rst new file mode 100644 index 00000000..341946ed --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.linux.ns3.rst @@ -0,0 +1,69 @@ +nepi.resources.linux.ns3 package +================================ + +Subpackages +----------- + +.. toctree:: + + nepi.resources.linux.ns3.ccn + +Submodules +---------- + +nepi.resources.linux.ns3.fdudptunnel module +------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.fdudptunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3client module +----------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3dceapplication module +------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3dceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3pingdceapplication module +----------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3pingdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3simulation module +--------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3simulation + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.tuntapfdlink module +-------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.tuntapfdlink + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.ns3 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.linux.rst b/doc/sphinx/_layout/nepi.resources.linux.rst new file mode 100644 index 00000000..40e4309b --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.linux.rst @@ -0,0 +1,167 @@ +nepi.resources.linux package +============================ + +Subpackages +----------- + +.. toctree:: + + nepi.resources.linux.ccn + nepi.resources.linux.netns + nepi.resources.linux.ns3 + +Submodules +---------- + +nepi.resources.linux.application module +--------------------------------------- + +.. automodule:: nepi.resources.linux.application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.channel module +----------------------------------- + +.. automodule:: nepi.resources.linux.channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.debfuncs module +------------------------------------ + +.. automodule:: nepi.resources.linux.debfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.gretunnel module +------------------------------------- + +.. automodule:: nepi.resources.linux.gretunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.interface module +------------------------------------- + +.. automodule:: nepi.resources.linux.interface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.mtr module +------------------------------- + +.. automodule:: nepi.resources.linux.mtr + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.node module +-------------------------------- + +.. automodule:: nepi.resources.linux.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.nping module +--------------------------------- + +.. automodule:: nepi.resources.linux.nping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ping module +-------------------------------- + +.. automodule:: nepi.resources.linux.ping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.route module +--------------------------------- + +.. automodule:: nepi.resources.linux.route + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.rpmfuncs module +------------------------------------ + +.. automodule:: nepi.resources.linux.rpmfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tap module +------------------------------- + +.. automodule:: nepi.resources.linux.tap + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tcpdump module +----------------------------------- + +.. automodule:: nepi.resources.linux.tcpdump + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.traceroute module +-------------------------------------- + +.. automodule:: nepi.resources.linux.traceroute + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tun module +------------------------------- + +.. automodule:: nepi.resources.linux.tun + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tunnel module +---------------------------------- + +.. automodule:: nepi.resources.linux.tunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.udptest module +----------------------------------- + +.. automodule:: nepi.resources.linux.udptest + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.udptunnel module +------------------------------------- + +.. automodule:: nepi.resources.linux.udptunnel + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.netns.rst b/doc/sphinx/_layout/nepi.resources.netns.rst new file mode 100644 index 00000000..eacf7f36 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.netns.rst @@ -0,0 +1,118 @@ +nepi.resources.netns package +============================ + +Submodules +---------- + +nepi.resources.netns.netnsapplication module +-------------------------------------------- + +.. automodule:: nepi.resources.netns.netnsapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsbase module +------------------------------------- + +.. automodule:: nepi.resources.netns.netnsbase + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsclient module +--------------------------------------- + +.. automodule:: nepi.resources.netns.netnsclient + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsemulation module +------------------------------------------ + +.. automodule:: nepi.resources.netns.netnsemulation + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsinterface module +------------------------------------------ + +.. automodule:: nepi.resources.netns.netnsinterface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsipv4address module +-------------------------------------------- + +.. automodule:: nepi.resources.netns.netnsipv4address + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsnode module +------------------------------------- + +.. automodule:: nepi.resources.netns.netnsnode + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsnodeinterface module +---------------------------------------------- + +.. automodule:: nepi.resources.netns.netnsnodeinterface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsroute module +-------------------------------------- + +.. automodule:: nepi.resources.netns.netnsroute + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsserver module +--------------------------------------- + +.. automodule:: nepi.resources.netns.netnsserver + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsswitch module +--------------------------------------- + +.. automodule:: nepi.resources.netns.netnsswitch + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnswrapper module +---------------------------------------- + +.. automodule:: nepi.resources.netns.netnswrapper + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnswrapper_debug module +---------------------------------------------- + +.. automodule:: nepi.resources.netns.netnswrapper_debug + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.netns + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.ns3.classes.rst b/doc/sphinx/_layout/nepi.resources.ns3.classes.rst new file mode 100644 index 00000000..e489b712 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.ns3.classes.rst @@ -0,0 +1,862 @@ +nepi.resources.ns3.classes package +================================== + +Submodules +---------- + +nepi.resources.ns3.classes.aarf_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.aarf_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.aarfcd_wifi_manager module +----------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.aarfcd_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.adhoc_wifi_mac module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.adhoc_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.aloha_noack_net_device module +-------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.aloha_noack_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.amrr_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.amrr_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ap_wifi_mac module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ap_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.arf_wifi_manager module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.arf_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.arp_l3protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.arp_l3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.base_station_net_device module +--------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.base_station_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.binary_error_model module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.binary_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.binary_error_sixlow_model module +----------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.binary_error_sixlow_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.bridge_channel module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.bridge_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.bridge_net_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.bridge_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.bulk_send_application module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.bulk_send_application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.burst_error_model module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.burst_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.cara_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.cara_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_acceleration_mobility_model module +---------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.constant_acceleration_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_position_mobility_model module +------------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_position_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_rate_wifi_manager module +------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_rate_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_speed_propagation_delay_model module +------------------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_speed_propagation_delay_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_velocity_mobility_model module +------------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_velocity_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.cost231propagation_loss_model module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.cost231propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.csma_channel module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.csma_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.csma_net_device module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.csma_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.drop_tail_queue module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.drop_tail_queue + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.dsrdsr_routing module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.dsrdsr_routing + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.emu_net_device module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.emu_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.error_channel module +----------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.error_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.error_channel_sixlow module +------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.error_channel_sixlow + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.error_net_device module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.error_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.fd_net_device module +----------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.fd_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.fixed_rss_loss_model module +------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.fixed_rss_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.friis_propagation_loss_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.friis_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.gauss_markov_mobility_model module +------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.gauss_markov_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.hierarchical_mobility_model module +------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.hierarchical_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model module +------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.icmpv4l4protocol module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.icmpv4l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.icmpv6l4protocol module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.icmpv6l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ideal_wifi_manager module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ideal_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ipv4l3protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.ipv4l3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model module +----------------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.jakes_propagation_loss_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.jakes_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model module +------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.list_error_model module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.list_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.log_distance_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.log_distance_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.loopback_net_device module +----------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.loopback_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lr_wpan_net_device module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lr_wpan_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lte_enb_net_device module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lte_enb_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lte_simple_net_device module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lte_simple_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lte_ue_net_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lte_ue_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.matrix_propagation_loss_model module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.matrix_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.mesh_point_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.mesh_point_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.mesh_wifi_interface_mac module +--------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.mesh_wifi_interface_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.minstrel_wifi_manager module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.minstrel_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.multi_model_spectrum_channel module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.multi_model_spectrum_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.nakagami_propagation_loss_model module +----------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.nakagami_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.nist_error_rate_model module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.nist_error_rate_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.node module +-------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.non_communicating_net_device module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.non_communicating_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ocb_wifi_mac module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ocb_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.oh_buildings_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.oh_buildings_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.okumura_hata_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.okumura_hata_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.on_off_application module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.on_off_application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.onoe_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.onoe_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.packet_sink module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.packet_sink + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ping6 module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ping6 + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.point_to_point_channel module +-------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.point_to_point_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.point_to_point_net_device module +----------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.point_to_point_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.point_to_point_remote_channel module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.point_to_point_remote_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.radvd module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.radvd + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_direction2d_mobility_model module +------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_direction2d_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_propagation_delay_model module +---------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_propagation_delay_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_propagation_loss_model module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_walk2d_mobility_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_walk2d_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_waypoint_mobility_model module +---------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_waypoint_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.range_propagation_loss_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.range_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.rate_error_model module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.rate_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.receive_list_error_model module +---------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.receive_list_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.red_queue module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.red_queue + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.rraa_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.rraa_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.simple_channel module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.simple_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.simple_net_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.simple_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.single_model_spectrum_channel module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.single_model_spectrum_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.six_low_pan_net_device module +-------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.six_low_pan_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.sta_wifi_mac module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.sta_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model module +----------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.subscriber_station_net_device module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.subscriber_station_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.tap_bridge module +-------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.tap_bridge + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.tcp_l4protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.tcp_l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.three_log_distance_propagation_loss_model module +--------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.three_log_distance_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model module +----------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.uan_channel module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.uan_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_client module +-------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_echo_client module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_echo_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_echo_server module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_echo_server + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_l4protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.udp_l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_server module +-------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_server + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_trace_client module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_trace_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.v4ping module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.v4ping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.virtual_net_device module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.virtual_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.waypoint_mobility_model module +--------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.waypoint_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.wifi_net_device module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.wifi_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.yans_error_rate_model module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.yans_error_rate_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.yans_wifi_channel module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.yans_wifi_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.yans_wifi_phy module +----------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.yans_wifi_phy + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.ns3.classes + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.ns3.rst b/doc/sphinx/_layout/nepi.resources.ns3.rst new file mode 100644 index 00000000..94356ab8 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.ns3.rst @@ -0,0 +1,269 @@ +nepi.resources.ns3 package +========================== + +Subpackages +----------- + +.. toctree:: + + nepi.resources.ns3.classes + +Submodules +---------- + +nepi.resources.ns3.ns3application module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3arpl3protocol module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3arpl3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3base module +--------------------------------- + +.. automodule:: nepi.resources.ns3.ns3base + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3ccndceapplication module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3ccndceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3channel module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3client module +----------------------------------- + +.. automodule:: nepi.resources.ns3.ns3client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3dceapplication module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3dceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3dcehelper module +-------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3dcehelper + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3errormodel module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3errormodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3errorratemodel module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3errorratemodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3fdnetdevice module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3fdnetdevice + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3icmpv4l4protocol module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3icmpv4l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3ipv4l3protocol module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3ipv4l3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3mobilitymodel module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3mobilitymodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3netdevice module +-------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3netdevice + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3node module +--------------------------------- + +.. automodule:: nepi.resources.ns3.ns3node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3pipechanel module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3pipechanel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3propagationdelaymodel module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3propagationdelaymodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3propagationlossmodel module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3propagationlossmodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3queue module +---------------------------------- + +.. automodule:: nepi.resources.ns3.ns3queue + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3route module +---------------------------------- + +.. automodule:: nepi.resources.ns3.ns3route + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3server module +----------------------------------- + +.. automodule:: nepi.resources.ns3.ns3server + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3simulation module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3simulation + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifichannel module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3wifichannel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifimac module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wifimac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifinetdevice module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wifinetdevice + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifiphy module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wifiphy + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifiremotestationmanager module +----------------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3wifiremotestationmanager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wrapper module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wrapper + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wrapper_debug module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wrapper_debug + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.resource_manager_generator module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.resource_manager_generator + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.ns3 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.omf.rst b/doc/sphinx/_layout/nepi.resources.omf.rst new file mode 100644 index 00000000..7dd222ee --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.omf.rst @@ -0,0 +1,118 @@ +nepi.resources.omf package +========================== + +Submodules +---------- + +nepi.resources.omf.application module +------------------------------------- + +.. automodule:: nepi.resources.omf.application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.channel module +--------------------------------- + +.. automodule:: nepi.resources.omf.channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.interface module +----------------------------------- + +.. automodule:: nepi.resources.omf.interface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.messages_5_4 module +-------------------------------------- + +.. automodule:: nepi.resources.omf.messages_5_4 + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.messages_6 module +------------------------------------ + +.. automodule:: nepi.resources.omf.messages_6 + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.node module +------------------------------ + +.. automodule:: nepi.resources.omf.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf5_api module +---------------------------------- + +.. automodule:: nepi.resources.omf.omf5_api + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf6_api module +---------------------------------- + +.. automodule:: nepi.resources.omf.omf6_api + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf6_parser module +------------------------------------- + +.. automodule:: nepi.resources.omf.omf6_parser + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf_api_factory module +----------------------------------------- + +.. automodule:: nepi.resources.omf.omf_api_factory + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf_client module +------------------------------------ + +.. automodule:: nepi.resources.omf.omf_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf_resource module +-------------------------------------- + +.. automodule:: nepi.resources.omf.omf_resource + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.wilabt_node module +------------------------------------- + +.. automodule:: nepi.resources.omf.wilabt_node + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.omf + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.planetlab.ns3.rst b/doc/sphinx/_layout/nepi.resources.planetlab.ns3.rst new file mode 100644 index 00000000..a8759d48 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.planetlab.ns3.rst @@ -0,0 +1,30 @@ +nepi.resources.planetlab.ns3 package +==================================== + +Submodules +---------- + +nepi.resources.planetlab.ns3.fdudptunnel module +----------------------------------------------- + +.. automodule:: nepi.resources.planetlab.ns3.fdudptunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.ns3.tuntapfdlink module +------------------------------------------------ + +.. automodule:: nepi.resources.planetlab.ns3.tuntapfdlink + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.planetlab.ns3 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.planetlab.openvswitch.rst b/doc/sphinx/_layout/nepi.resources.planetlab.openvswitch.rst new file mode 100644 index 00000000..edbb21a2 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.planetlab.openvswitch.rst @@ -0,0 +1,30 @@ +nepi.resources.planetlab.openvswitch package +============================================ + +Submodules +---------- + +nepi.resources.planetlab.openvswitch.ovs module +----------------------------------------------- + +.. automodule:: nepi.resources.planetlab.openvswitch.ovs + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.openvswitch.ovsport module +--------------------------------------------------- + +.. automodule:: nepi.resources.planetlab.openvswitch.ovsport + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.planetlab.openvswitch + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.planetlab.rst b/doc/sphinx/_layout/nepi.resources.planetlab.rst new file mode 100644 index 00000000..9fde12c9 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.planetlab.rst @@ -0,0 +1,70 @@ +nepi.resources.planetlab package +================================ + +Subpackages +----------- + +.. toctree:: + + nepi.resources.planetlab.ns3 + nepi.resources.planetlab.openvswitch + +Submodules +---------- + +nepi.resources.planetlab.node module +------------------------------------ + +.. automodule:: nepi.resources.planetlab.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.plcapi module +-------------------------------------- + +.. automodule:: nepi.resources.planetlab.plcapi + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.sfa_node module +---------------------------------------- + +.. automodule:: nepi.resources.planetlab.sfa_node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.tap module +----------------------------------- + +.. automodule:: nepi.resources.planetlab.tap + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.tun module +----------------------------------- + +.. automodule:: nepi.resources.planetlab.tun + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.vroute module +-------------------------------------- + +.. automodule:: nepi.resources.planetlab.vroute + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.planetlab + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.rst b/doc/sphinx/_layout/nepi.resources.rst new file mode 100644 index 00000000..4c1fcfc2 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.rst @@ -0,0 +1,22 @@ +nepi.resources package +====================== + +Subpackages +----------- + +.. toctree:: + + nepi.resources.all + nepi.resources.linux + nepi.resources.netns + nepi.resources.ns3 + nepi.resources.omf + nepi.resources.planetlab + +Module contents +--------------- + +.. automodule:: nepi.resources + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.rst b/doc/sphinx/_layout/nepi.rst new file mode 100644 index 00000000..aa1d5d30 --- /dev/null +++ b/doc/sphinx/_layout/nepi.rst @@ -0,0 +1,20 @@ +nepi package +============ + +Subpackages +----------- + +.. toctree:: + + nepi.data + nepi.execution + nepi.resources + nepi.util + +Module contents +--------------- + +.. automodule:: nepi + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.util.parsers.rst b/doc/sphinx/_layout/nepi.util.parsers.rst new file mode 100644 index 00000000..34888c17 --- /dev/null +++ b/doc/sphinx/_layout/nepi.util.parsers.rst @@ -0,0 +1,22 @@ +nepi.util.parsers package +========================= + +Submodules +---------- + +nepi.util.parsers.xml_parser module +----------------------------------- + +.. automodule:: nepi.util.parsers.xml_parser + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.util.parsers + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.util.rst b/doc/sphinx/_layout/nepi.util.rst new file mode 100644 index 00000000..cf0bc639 --- /dev/null +++ b/doc/sphinx/_layout/nepi.util.rst @@ -0,0 +1,141 @@ +nepi.util package +================= + +Subpackages +----------- + +.. toctree:: + + nepi.util.parsers + +Submodules +---------- + +nepi.util.environ module +------------------------ + +.. automodule:: nepi.util.environ + :members: + :undoc-members: + :show-inheritance: + +nepi.util.execfuncs module +-------------------------- + +.. automodule:: nepi.util.execfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.util.guid module +--------------------- + +.. automodule:: nepi.util.guid + :members: + :undoc-members: + :show-inheritance: + +nepi.util.logger module +----------------------- + +.. automodule:: nepi.util.logger + :members: + :undoc-members: + :show-inheritance: + +nepi.util.manifoldapi module +---------------------------- + +.. automodule:: nepi.util.manifoldapi + :members: + :undoc-members: + :show-inheritance: + +nepi.util.netgraph module +------------------------- + +.. automodule:: nepi.util.netgraph + :members: + :undoc-members: + :show-inheritance: + +nepi.util.parallel module +------------------------- + +.. automodule:: nepi.util.parallel + :members: + :undoc-members: + :show-inheritance: + +nepi.util.plotter module +------------------------ + +.. automodule:: nepi.util.plotter + :members: + :undoc-members: + :show-inheritance: + +nepi.util.rmatcher module +------------------------- + +.. automodule:: nepi.util.rmatcher + :members: + :undoc-members: + :show-inheritance: + +nepi.util.serializer module +--------------------------- + +.. automodule:: nepi.util.serializer + :members: + :undoc-members: + :show-inheritance: + +nepi.util.sfaapi module +----------------------- + +.. automodule:: nepi.util.sfaapi + :members: + :undoc-members: + :show-inheritance: + +nepi.util.sfarspec_proc module +------------------------------ + +.. automodule:: nepi.util.sfarspec_proc + :members: + :undoc-members: + :show-inheritance: + +nepi.util.sshfuncs module +------------------------- + +.. automodule:: nepi.util.sshfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.util.statfuncs module +-------------------------- + +.. automodule:: nepi.util.statfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.util.timefuncs module +-------------------------- + +.. automodule:: nepi.util.timefuncs + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.util + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/conf.py b/doc/sphinx/conf.py new file mode 100644 index 00000000..188ce2ae --- /dev/null +++ b/doc/sphinx/conf.py @@ -0,0 +1,247 @@ +# -*- coding: utf-8 -*- +# +# Nepi documentation build configuration file, created by +# sphinx-quickstart on Tue Mar 25 16:32:00 2014. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('../../src')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'NEPI' +copyright = u'2014, Alina Quereilhac, Lucia Guevgeozian Odizzio, Julien Tribino' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '3' +# The full version, including alpha/beta/rc tags. +release = '3.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'sphinxdoc' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Nepidoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'NEPI.tex', u'NEPI Documentation', + u'Alina Quereilhac, Lucia Guevgeozian Odizzio, Julien Tribino', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'NEPI', u'NEPI Documentation', + [u'Alina Quereilhac, Lucia Guevgeozian Odizzio, Julien Tribino'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'NEPI', u'NEPI Documentation', + u'Alina Quereilhac, Lucia Guevgeozian Odizzio, Julien Tribino', + 'NEPI', 'The network experimentation programming interface', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst new file mode 100644 index 00000000..6cc4c839 --- /dev/null +++ b/doc/sphinx/index.rst @@ -0,0 +1,91 @@ +.. Nepi documentation master file, created by + sphinx-quickstart on Tue Mar 26 11:36:35 2013. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +NEPI modules +============ + +This page documents the NEPI source code. It presents the NEPI core modules, the Platform resource modules (i.e. drivers to manage platforms), and other miscellaneous classes. + +Core modules +------------ + + * ExperimentController API + + * :mod:`ExperimentController ` + + * ResourceManager API + + * :mod:`ResourceManager ` + + * Attribute module + + * :mod:`Attribute ` + + * Trace module + + * :mod:`Trace ` + + * Runner module + + * :mod:`ExperimentRunner ` + + * Scheduler module + + * :mod:`Scheduler ` + + + +Platform modules +---------------- + + * Live Experiments + + * Linux testbeds + + * :mod:`Linux ` + + * PlanetLab testbeds + + * :mod:`PlanetLab ` + + * OMF testbed + + * :mod:`OMF ` + + * Simulated Experiments + + * ns-3 simulator + + * :mod:`ns-3 ` + + * :mod:`ns-3 in Linux hosts ` + + * Emulated Experiments + + * DCE emulation extension + + * :mod:`DCE Application ` + + * :mod:`DCE Linux Application ` + + * NetNS emulator + + * :mod:`NetNS ` + +Miscellaneous modules +--------------------- + + * :mod:`Util ` + +.. toctree:: + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + -- 2.43.0