diff --git a/docs/_build/.DS_Store b/docs/_build/.DS_Store new file mode 100644 index 0000000..2c3e9ff Binary files /dev/null and b/docs/_build/.DS_Store differ diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo new file mode 100644 index 0000000..c5b5d2c --- /dev/null +++ b/docs/_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: 877a467e62892ff1022262f37f485127 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/_build/html/.doctrees/activating_agents.doctree b/docs/_build/html/.doctrees/activating_agents.doctree new file mode 100644 index 0000000..4040580 Binary files /dev/null and b/docs/_build/html/.doctrees/activating_agents.doctree differ diff --git a/docs/_build/html/.doctrees/adding_a_behavior_to_an_agent.doctree b/docs/_build/html/.doctrees/adding_a_behavior_to_an_agent.doctree new file mode 100644 index 0000000..3c36825 Binary files /dev/null and b/docs/_build/html/.doctrees/adding_a_behavior_to_an_agent.doctree differ diff --git a/docs/_build/html/.doctrees/base_class_methods.doctree b/docs/_build/html/.doctrees/base_class_methods.doctree new file mode 100644 index 0000000..dcf19b9 Binary files /dev/null and b/docs/_build/html/.doctrees/base_class_methods.doctree differ diff --git a/docs/_build/html/.doctrees/building_an_agent_network.doctree b/docs/_build/html/.doctrees/building_an_agent_network.doctree new file mode 100644 index 0000000..92ddcb7 Binary files /dev/null and b/docs/_build/html/.doctrees/building_an_agent_network.doctree differ diff --git a/docs/_build/html/.doctrees/capturing_the_test_results.doctree b/docs/_build/html/.doctrees/capturing_the_test_results.doctree new file mode 100644 index 0000000..a766234 Binary files /dev/null and b/docs/_build/html/.doctrees/capturing_the_test_results.doctree differ diff --git a/docs/_build/html/.doctrees/changelog.doctree b/docs/_build/html/.doctrees/changelog.doctree new file mode 100644 index 0000000..a979d09 Binary files /dev/null and b/docs/_build/html/.doctrees/changelog.doctree differ diff --git a/docs/_build/html/.doctrees/connecting_a_node_to_the_server.doctree b/docs/_build/html/.doctrees/connecting_a_node_to_the_server.doctree new file mode 100644 index 0000000..98766fa Binary files /dev/null and b/docs/_build/html/.doctrees/connecting_a_node_to_the_server.doctree differ diff --git a/docs/_build/html/.doctrees/contact_us.doctree b/docs/_build/html/.doctrees/contact_us.doctree new file mode 100644 index 0000000..d2bd7d9 Binary files /dev/null and b/docs/_build/html/.doctrees/contact_us.doctree differ diff --git a/docs/_build/html/.doctrees/creating_a_test_case_using_robot_framework.doctree b/docs/_build/html/.doctrees/creating_a_test_case_using_robot_framework.doctree new file mode 100644 index 0000000..1af3552 Binary files /dev/null and b/docs/_build/html/.doctrees/creating_a_test_case_using_robot_framework.doctree differ diff --git a/docs/_build/html/.doctrees/creating_your_own_controller_application.doctree b/docs/_build/html/.doctrees/creating_your_own_controller_application.doctree new file mode 100644 index 0000000..e48a1e4 Binary files /dev/null and b/docs/_build/html/.doctrees/creating_your_own_controller_application.doctree differ diff --git a/docs/_build/html/.doctrees/environment.pickle b/docs/_build/html/.doctrees/environment.pickle new file mode 100644 index 0000000..0c6ab7e Binary files /dev/null and b/docs/_build/html/.doctrees/environment.pickle differ diff --git a/docs/_build/html/.doctrees/example.doctree b/docs/_build/html/.doctrees/example.doctree new file mode 100644 index 0000000..f91b1d3 Binary files /dev/null and b/docs/_build/html/.doctrees/example.doctree differ diff --git a/docs/_build/html/.doctrees/features.doctree b/docs/_build/html/.doctrees/features.doctree new file mode 100644 index 0000000..4332d22 Binary files /dev/null and b/docs/_build/html/.doctrees/features.doctree differ diff --git a/docs/_build/html/.doctrees/help.doctree b/docs/_build/html/.doctrees/help.doctree new file mode 100644 index 0000000..fbf9e4c Binary files /dev/null and b/docs/_build/html/.doctrees/help.doctree differ diff --git a/docs/_build/html/.doctrees/how_it_works.doctree b/docs/_build/html/.doctrees/how_it_works.doctree new file mode 100644 index 0000000..6bf7f0c Binary files /dev/null and b/docs/_build/html/.doctrees/how_it_works.doctree differ diff --git a/docs/_build/html/.doctrees/index.doctree b/docs/_build/html/.doctrees/index.doctree new file mode 100644 index 0000000..497484b Binary files /dev/null and b/docs/_build/html/.doctrees/index.doctree differ diff --git a/docs/_build/html/.doctrees/installation.doctree b/docs/_build/html/.doctrees/installation.doctree new file mode 100644 index 0000000..083864b Binary files /dev/null and b/docs/_build/html/.doctrees/installation.doctree differ diff --git a/docs/_build/html/.doctrees/introduction.doctree b/docs/_build/html/.doctrees/introduction.doctree new file mode 100644 index 0000000..46d5a76 Binary files /dev/null and b/docs/_build/html/.doctrees/introduction.doctree differ diff --git a/docs/_build/html/.doctrees/managing_behavior_files.doctree b/docs/_build/html/.doctrees/managing_behavior_files.doctree new file mode 100644 index 0000000..0979e27 Binary files /dev/null and b/docs/_build/html/.doctrees/managing_behavior_files.doctree differ diff --git a/docs/_build/html/.doctrees/responding_to_a_message_sent_to_an_agent.doctree b/docs/_build/html/.doctrees/responding_to_a_message_sent_to_an_agent.doctree new file mode 100644 index 0000000..8959a24 Binary files /dev/null and b/docs/_build/html/.doctrees/responding_to_a_message_sent_to_an_agent.doctree differ diff --git a/docs/_build/html/.doctrees/retrieving_information_about_your_agent_network.doctree b/docs/_build/html/.doctrees/retrieving_information_about_your_agent_network.doctree new file mode 100644 index 0000000..ee31594 Binary files /dev/null and b/docs/_build/html/.doctrees/retrieving_information_about_your_agent_network.doctree differ diff --git a/docs/_build/html/.doctrees/robot_framework_background.doctree b/docs/_build/html/.doctrees/robot_framework_background.doctree new file mode 100644 index 0000000..de28d11 Binary files /dev/null and b/docs/_build/html/.doctrees/robot_framework_background.doctree differ diff --git a/docs/_build/html/.doctrees/running_your_automation_test.doctree b/docs/_build/html/.doctrees/running_your_automation_test.doctree new file mode 100644 index 0000000..dd24044 Binary files /dev/null and b/docs/_build/html/.doctrees/running_your_automation_test.doctree differ diff --git a/docs/_build/html/.doctrees/sage3_app.doctree b/docs/_build/html/.doctrees/sage3_app.doctree new file mode 100644 index 0000000..5671961 Binary files /dev/null and b/docs/_build/html/.doctrees/sage3_app.doctree differ diff --git a/docs/_build/html/.doctrees/sage_app.doctree b/docs/_build/html/.doctrees/sage_app.doctree new file mode 100644 index 0000000..05c6657 Binary files /dev/null and b/docs/_build/html/.doctrees/sage_app.doctree differ diff --git a/docs/_build/html/.doctrees/sage_node.doctree b/docs/_build/html/.doctrees/sage_node.doctree new file mode 100644 index 0000000..27657b2 Binary files /dev/null and b/docs/_build/html/.doctrees/sage_node.doctree differ diff --git a/docs/_build/html/.doctrees/sage_robot_framework_keywords.doctree b/docs/_build/html/.doctrees/sage_robot_framework_keywords.doctree new file mode 100644 index 0000000..688ea33 Binary files /dev/null and b/docs/_build/html/.doctrees/sage_robot_framework_keywords.doctree differ diff --git a/docs/_build/html/.doctrees/sage_server.doctree b/docs/_build/html/.doctrees/sage_server.doctree new file mode 100644 index 0000000..acc362a Binary files /dev/null and b/docs/_build/html/.doctrees/sage_server.doctree differ diff --git a/docs/_build/html/.doctrees/sending_messages_between_agents.doctree b/docs/_build/html/.doctrees/sending_messages_between_agents.doctree new file mode 100644 index 0000000..80b4148 Binary files /dev/null and b/docs/_build/html/.doctrees/sending_messages_between_agents.doctree differ diff --git a/docs/_build/html/.doctrees/starting_a_server_instance.doctree b/docs/_build/html/.doctrees/starting_a_server_instance.doctree new file mode 100644 index 0000000..6aebda9 Binary files /dev/null and b/docs/_build/html/.doctrees/starting_a_server_instance.doctree differ diff --git a/docs/_build/html/.doctrees/using_supplemental_files_in_your_automation.doctree b/docs/_build/html/.doctrees/using_supplemental_files_in_your_automation.doctree new file mode 100644 index 0000000..f831a66 Binary files /dev/null and b/docs/_build/html/.doctrees/using_supplemental_files_in_your_automation.doctree differ diff --git a/docs/_build/html/.doctrees/writing_a_sage_behavior.doctree b/docs/_build/html/.doctrees/writing_a_sage_behavior.doctree new file mode 100644 index 0000000..af4e64f Binary files /dev/null and b/docs/_build/html/.doctrees/writing_a_sage_behavior.doctree differ diff --git a/docs/_build/html/_images/SageCluster.png b/docs/_build/html/_images/SageCluster.png new file mode 100644 index 0000000..ecf40c6 Binary files /dev/null and b/docs/_build/html/_images/SageCluster.png differ diff --git a/docs/_build/html/_images/SageClusters.png b/docs/_build/html/_images/SageClusters.png new file mode 100644 index 0000000..8f997c1 Binary files /dev/null and b/docs/_build/html/_images/SageClusters.png differ diff --git a/docs/_build/html/_images/Sage_Node.png b/docs/_build/html/_images/Sage_Node.png new file mode 100644 index 0000000..54286ed Binary files /dev/null and b/docs/_build/html/_images/Sage_Node.png differ diff --git a/docs/_build/html/_images/Sage_Server.png b/docs/_build/html/_images/Sage_Server.png new file mode 100644 index 0000000..170875f Binary files /dev/null and b/docs/_build/html/_images/Sage_Server.png differ diff --git a/docs/_build/html/_images/active_server_1.png b/docs/_build/html/_images/active_server_1.png new file mode 100644 index 0000000..8e3187f Binary files /dev/null and b/docs/_build/html/_images/active_server_1.png differ diff --git a/docs/_build/html/_images/active_server_10.png b/docs/_build/html/_images/active_server_10.png new file mode 100644 index 0000000..b043679 Binary files /dev/null and b/docs/_build/html/_images/active_server_10.png differ diff --git a/docs/_build/html/_images/active_server_11.png b/docs/_build/html/_images/active_server_11.png new file mode 100644 index 0000000..46976bc Binary files /dev/null and b/docs/_build/html/_images/active_server_11.png differ diff --git a/docs/_build/html/_images/active_server_2.png b/docs/_build/html/_images/active_server_2.png new file mode 100644 index 0000000..3c23985 Binary files /dev/null and b/docs/_build/html/_images/active_server_2.png differ diff --git a/docs/_build/html/_images/active_server_3.png b/docs/_build/html/_images/active_server_3.png new file mode 100644 index 0000000..72c9d0c Binary files /dev/null and b/docs/_build/html/_images/active_server_3.png differ diff --git a/docs/_build/html/_images/active_server_4.png b/docs/_build/html/_images/active_server_4.png new file mode 100644 index 0000000..c941ac5 Binary files /dev/null and b/docs/_build/html/_images/active_server_4.png differ diff --git a/docs/_build/html/_images/active_server_5.png b/docs/_build/html/_images/active_server_5.png new file mode 100644 index 0000000..25888d2 Binary files /dev/null and b/docs/_build/html/_images/active_server_5.png differ diff --git a/docs/_build/html/_images/active_server_6.png b/docs/_build/html/_images/active_server_6.png new file mode 100644 index 0000000..bf8d194 Binary files /dev/null and b/docs/_build/html/_images/active_server_6.png differ diff --git a/docs/_build/html/_images/active_server_7.png b/docs/_build/html/_images/active_server_7.png new file mode 100644 index 0000000..4ac56ab Binary files /dev/null and b/docs/_build/html/_images/active_server_7.png differ diff --git a/docs/_build/html/_images/active_server_8.png b/docs/_build/html/_images/active_server_8.png new file mode 100644 index 0000000..aab3554 Binary files /dev/null and b/docs/_build/html/_images/active_server_8.png differ diff --git a/docs/_build/html/_images/active_server_9.png b/docs/_build/html/_images/active_server_9.png new file mode 100644 index 0000000..6aa2224 Binary files /dev/null and b/docs/_build/html/_images/active_server_9.png differ diff --git a/docs/_build/html/_images/active_server_logger.png b/docs/_build/html/_images/active_server_logger.png new file mode 100644 index 0000000..1958cac Binary files /dev/null and b/docs/_build/html/_images/active_server_logger.png differ diff --git a/docs/_build/html/_images/add_behavior.png b/docs/_build/html/_images/add_behavior.png new file mode 100644 index 0000000..63d9b5f Binary files /dev/null and b/docs/_build/html/_images/add_behavior.png differ diff --git a/docs/_build/html/_images/behavior_manager.png b/docs/_build/html/_images/behavior_manager.png new file mode 100644 index 0000000..2036259 Binary files /dev/null and b/docs/_build/html/_images/behavior_manager.png differ diff --git a/docs/_build/html/_images/behavior_topics.png b/docs/_build/html/_images/behavior_topics.png new file mode 100644 index 0000000..1ae0d8b Binary files /dev/null and b/docs/_build/html/_images/behavior_topics.png differ diff --git a/docs/_build/html/_images/create_agent.png b/docs/_build/html/_images/create_agent.png new file mode 100644 index 0000000..fde6e61 Binary files /dev/null and b/docs/_build/html/_images/create_agent.png differ diff --git a/docs/_build/html/_images/create_node.png b/docs/_build/html/_images/create_node.png new file mode 100644 index 0000000..efa74d0 Binary files /dev/null and b/docs/_build/html/_images/create_node.png differ diff --git a/docs/_build/html/_images/features_1.png b/docs/_build/html/_images/features_1.png new file mode 100644 index 0000000..80af9e8 Binary files /dev/null and b/docs/_build/html/_images/features_1.png differ diff --git a/docs/_build/html/_images/features_2.png b/docs/_build/html/_images/features_2.png new file mode 100644 index 0000000..1136414 Binary files /dev/null and b/docs/_build/html/_images/features_2.png differ diff --git a/docs/_build/html/_images/features_3.png b/docs/_build/html/_images/features_3.png new file mode 100644 index 0000000..ada5f4f Binary files /dev/null and b/docs/_build/html/_images/features_3.png differ diff --git a/docs/_build/html/_images/features_4.png b/docs/_build/html/_images/features_4.png new file mode 100644 index 0000000..8367685 Binary files /dev/null and b/docs/_build/html/_images/features_4.png differ diff --git a/docs/_build/html/_images/features_5.png b/docs/_build/html/_images/features_5.png new file mode 100644 index 0000000..c02d3d3 Binary files /dev/null and b/docs/_build/html/_images/features_5.png differ diff --git a/docs/_build/html/_images/image1.png b/docs/_build/html/_images/image1.png new file mode 100644 index 0000000..6978874 Binary files /dev/null and b/docs/_build/html/_images/image1.png differ diff --git a/docs/_build/html/_images/image10.png b/docs/_build/html/_images/image10.png new file mode 100644 index 0000000..862bffd Binary files /dev/null and b/docs/_build/html/_images/image10.png differ diff --git a/docs/_build/html/_images/image11.png b/docs/_build/html/_images/image11.png new file mode 100644 index 0000000..cad8903 Binary files /dev/null and b/docs/_build/html/_images/image11.png differ diff --git a/docs/_build/html/_images/image12.png b/docs/_build/html/_images/image12.png new file mode 100644 index 0000000..44e4bf9 Binary files /dev/null and b/docs/_build/html/_images/image12.png differ diff --git a/docs/_build/html/_images/image13.png b/docs/_build/html/_images/image13.png new file mode 100644 index 0000000..90bcefa Binary files /dev/null and b/docs/_build/html/_images/image13.png differ diff --git a/docs/_build/html/_images/image14.png b/docs/_build/html/_images/image14.png new file mode 100644 index 0000000..29afb10 Binary files /dev/null and b/docs/_build/html/_images/image14.png differ diff --git a/docs/_build/html/_images/image15.png b/docs/_build/html/_images/image15.png new file mode 100644 index 0000000..5825458 Binary files /dev/null and b/docs/_build/html/_images/image15.png differ diff --git a/docs/_build/html/_images/image16.png b/docs/_build/html/_images/image16.png new file mode 100644 index 0000000..8852e10 Binary files /dev/null and b/docs/_build/html/_images/image16.png differ diff --git a/docs/_build/html/_images/image17.png b/docs/_build/html/_images/image17.png new file mode 100644 index 0000000..6e8585d Binary files /dev/null and b/docs/_build/html/_images/image17.png differ diff --git a/docs/_build/html/_images/image18.png b/docs/_build/html/_images/image18.png new file mode 100644 index 0000000..ca1bfb4 Binary files /dev/null and b/docs/_build/html/_images/image18.png differ diff --git a/docs/_build/html/_images/image19.png b/docs/_build/html/_images/image19.png new file mode 100644 index 0000000..c3807ee Binary files /dev/null and b/docs/_build/html/_images/image19.png differ diff --git a/docs/_build/html/_images/image2.png b/docs/_build/html/_images/image2.png new file mode 100644 index 0000000..9c17af0 Binary files /dev/null and b/docs/_build/html/_images/image2.png differ diff --git a/docs/_build/html/_images/image20.png b/docs/_build/html/_images/image20.png new file mode 100644 index 0000000..d496a17 Binary files /dev/null and b/docs/_build/html/_images/image20.png differ diff --git a/docs/_build/html/_images/image21.png b/docs/_build/html/_images/image21.png new file mode 100644 index 0000000..e2a1eb2 Binary files /dev/null and b/docs/_build/html/_images/image21.png differ diff --git a/docs/_build/html/_images/image22.png b/docs/_build/html/_images/image22.png new file mode 100644 index 0000000..3d42a49 Binary files /dev/null and b/docs/_build/html/_images/image22.png differ diff --git a/docs/_build/html/_images/image23.png b/docs/_build/html/_images/image23.png new file mode 100644 index 0000000..94a7deb Binary files /dev/null and b/docs/_build/html/_images/image23.png differ diff --git a/docs/_build/html/_images/image24.png b/docs/_build/html/_images/image24.png new file mode 100644 index 0000000..49c1e2f Binary files /dev/null and b/docs/_build/html/_images/image24.png differ diff --git a/docs/_build/html/_images/image25.png b/docs/_build/html/_images/image25.png new file mode 100644 index 0000000..226d3de Binary files /dev/null and b/docs/_build/html/_images/image25.png differ diff --git a/docs/_build/html/_images/image26.png b/docs/_build/html/_images/image26.png new file mode 100644 index 0000000..bdccae5 Binary files /dev/null and b/docs/_build/html/_images/image26.png differ diff --git a/docs/_build/html/_images/image27.png b/docs/_build/html/_images/image27.png new file mode 100644 index 0000000..56d9152 Binary files /dev/null and b/docs/_build/html/_images/image27.png differ diff --git a/docs/_build/html/_images/image28.png b/docs/_build/html/_images/image28.png new file mode 100644 index 0000000..27e0144 Binary files /dev/null and b/docs/_build/html/_images/image28.png differ diff --git a/docs/_build/html/_images/image29.png b/docs/_build/html/_images/image29.png new file mode 100644 index 0000000..8f2e537 Binary files /dev/null and b/docs/_build/html/_images/image29.png differ diff --git a/docs/_build/html/_images/image3.png b/docs/_build/html/_images/image3.png new file mode 100644 index 0000000..8b3dd88 Binary files /dev/null and b/docs/_build/html/_images/image3.png differ diff --git a/docs/_build/html/_images/image30.png b/docs/_build/html/_images/image30.png new file mode 100644 index 0000000..c9e1ad5 Binary files /dev/null and b/docs/_build/html/_images/image30.png differ diff --git a/docs/_build/html/_images/image31.png b/docs/_build/html/_images/image31.png new file mode 100644 index 0000000..1f80058 Binary files /dev/null and b/docs/_build/html/_images/image31.png differ diff --git a/docs/_build/html/_images/image32.png b/docs/_build/html/_images/image32.png new file mode 100644 index 0000000..ef7da15 Binary files /dev/null and b/docs/_build/html/_images/image32.png differ diff --git a/docs/_build/html/_images/image33.png b/docs/_build/html/_images/image33.png new file mode 100644 index 0000000..5ab5128 Binary files /dev/null and b/docs/_build/html/_images/image33.png differ diff --git a/docs/_build/html/_images/image34.png b/docs/_build/html/_images/image34.png new file mode 100644 index 0000000..0eaa496 Binary files /dev/null and b/docs/_build/html/_images/image34.png differ diff --git a/docs/_build/html/_images/image4.png b/docs/_build/html/_images/image4.png new file mode 100644 index 0000000..50899a0 Binary files /dev/null and b/docs/_build/html/_images/image4.png differ diff --git a/docs/_build/html/_images/image5.png b/docs/_build/html/_images/image5.png new file mode 100644 index 0000000..6281948 Binary files /dev/null and b/docs/_build/html/_images/image5.png differ diff --git a/docs/_build/html/_images/image6.png b/docs/_build/html/_images/image6.png new file mode 100644 index 0000000..c1925fc Binary files /dev/null and b/docs/_build/html/_images/image6.png differ diff --git a/docs/_build/html/_images/image7.png b/docs/_build/html/_images/image7.png new file mode 100644 index 0000000..f43465b Binary files /dev/null and b/docs/_build/html/_images/image7.png differ diff --git a/docs/_build/html/_images/image8.png b/docs/_build/html/_images/image8.png new file mode 100644 index 0000000..6393624 Binary files /dev/null and b/docs/_build/html/_images/image8.png differ diff --git a/docs/_build/html/_images/image9.png b/docs/_build/html/_images/image9.png new file mode 100644 index 0000000..55e760c Binary files /dev/null and b/docs/_build/html/_images/image9.png differ diff --git a/docs/_build/html/_images/introduction_1.png b/docs/_build/html/_images/introduction_1.png new file mode 100644 index 0000000..6529621 Binary files /dev/null and b/docs/_build/html/_images/introduction_1.png differ diff --git a/docs/_build/html/_images/log_example.png b/docs/_build/html/_images/log_example.png new file mode 100644 index 0000000..cf3df22 Binary files /dev/null and b/docs/_build/html/_images/log_example.png differ diff --git a/docs/_build/html/_images/main_window.png b/docs/_build/html/_images/main_window.png new file mode 100644 index 0000000..23727cf Binary files /dev/null and b/docs/_build/html/_images/main_window.png differ diff --git a/docs/_build/html/_images/network_load_errors.png b/docs/_build/html/_images/network_load_errors.png new file mode 100644 index 0000000..92a3a7d Binary files /dev/null and b/docs/_build/html/_images/network_load_errors.png differ diff --git a/docs/_build/html/_images/robot_interface_1.png b/docs/_build/html/_images/robot_interface_1.png new file mode 100644 index 0000000..482b058 Binary files /dev/null and b/docs/_build/html/_images/robot_interface_1.png differ diff --git a/docs/_build/html/_images/robot_interface_2.png b/docs/_build/html/_images/robot_interface_2.png new file mode 100644 index 0000000..2e4d1f8 Binary files /dev/null and b/docs/_build/html/_images/robot_interface_2.png differ diff --git a/docs/_build/html/_images/sage_architecture.png b/docs/_build/html/_images/sage_architecture.png new file mode 100644 index 0000000..acb091e Binary files /dev/null and b/docs/_build/html/_images/sage_architecture.png differ diff --git a/docs/_build/html/_images/sage_network.png b/docs/_build/html/_images/sage_network.png new file mode 100644 index 0000000..1e12562 Binary files /dev/null and b/docs/_build/html/_images/sage_network.png differ diff --git a/docs/_build/html/_images/send_message_to_node.png b/docs/_build/html/_images/send_message_to_node.png new file mode 100644 index 0000000..85a7ae3 Binary files /dev/null and b/docs/_build/html/_images/send_message_to_node.png differ diff --git a/docs/_build/html/_images/send_message_to_node_2.png b/docs/_build/html/_images/send_message_to_node_2.png new file mode 100644 index 0000000..e717362 Binary files /dev/null and b/docs/_build/html/_images/send_message_to_node_2.png differ diff --git a/docs/_build/html/_images/server_settings.png b/docs/_build/html/_images/server_settings.png new file mode 100644 index 0000000..a4099e5 Binary files /dev/null and b/docs/_build/html/_images/server_settings.png differ diff --git a/docs/_build/html/_images/setup_begin.png b/docs/_build/html/_images/setup_begin.png new file mode 100644 index 0000000..ece8f01 Binary files /dev/null and b/docs/_build/html/_images/setup_begin.png differ diff --git a/docs/_build/html/_images/setup_complete.png b/docs/_build/html/_images/setup_complete.png new file mode 100644 index 0000000..e749995 Binary files /dev/null and b/docs/_build/html/_images/setup_complete.png differ diff --git a/docs/_build/html/_images/setup_filePath.png b/docs/_build/html/_images/setup_filePath.png new file mode 100644 index 0000000..1c43dde Binary files /dev/null and b/docs/_build/html/_images/setup_filePath.png differ diff --git a/docs/_build/html/_images/setup_license.PNG b/docs/_build/html/_images/setup_license.PNG new file mode 100644 index 0000000..93d3bf7 Binary files /dev/null and b/docs/_build/html/_images/setup_license.PNG differ diff --git a/docs/_build/html/_images/setup_ready.png b/docs/_build/html/_images/setup_ready.png new file mode 100644 index 0000000..3520feb Binary files /dev/null and b/docs/_build/html/_images/setup_ready.png differ diff --git a/docs/_build/html/_images/visual_c_install.png b/docs/_build/html/_images/visual_c_install.png new file mode 100644 index 0000000..d71a0a5 Binary files /dev/null and b/docs/_build/html/_images/visual_c_install.png differ diff --git a/docs/_build/html/_sources/activating_agents.rst.txt b/docs/_build/html/_sources/activating_agents.rst.txt new file mode 100644 index 0000000..9747f87 --- /dev/null +++ b/docs/_build/html/_sources/activating_agents.rst.txt @@ -0,0 +1,32 @@ +Activating Agents +======================================================= + +Remember that depending on how your Agents' Behaviors are programmed, Agents may execute code in response to being activated. + + +Agent entities can be activated in multiple ways. + +**Using the SAGE App** - You can activate your existing Agents using the SAGE App. This method is a fast way to activate a large number of agents simultaneously on a single Node. + + 1) In the SAGE App, select the targeted Node name or single Agent name and click :mod:`Activate Agent`. + +**By a Controller Appliction** - You can activate agents using a Controller Application, such as Robot Framework. This method is a fast way to activate a large number of single Agents across multiple Nodes. + + 1) Use the :mod:`Activate Agent` keyword to activate a targeted Agent name residing on the targeted Node. + + .. code-block:: bat + + Activate Agent nodeName1 newAgentName1 + Activate Agent nodeName1 newAgentName2 + Activate Agent nodeName2 newAgentName1 + +**Through the execution of a Behavior** - Agents have the ability to activate other agent entities. This is a dynamic way to build your agent network to be more robust. This unique SAGE capability is supported by activating agents within your SAGE Behavior code. This enables agents to activate other agents. + + 1) In your Behavior file, use the :mod:`setAgentActive` method to activate a targeted Agent name residing on the targeted Node. + 2) Set the value to *true* to activate or *false* to deactivate. + + .. code-block:: bat + + setAgentActive(nodeName1, newAgentName2, true); + setAgentActive(nodeName1, newAgentName2, false); + \ No newline at end of file diff --git a/docs/_build/html/_sources/adding_a_behavior_to_an_agent.rst.txt b/docs/_build/html/_sources/adding_a_behavior_to_an_agent.rst.txt new file mode 100644 index 0000000..5abe6be --- /dev/null +++ b/docs/_build/html/_sources/adding_a_behavior_to_an_agent.rst.txt @@ -0,0 +1,33 @@ +Adding a Behavior to an Agent +============================================================ + +The Server will distribute behavior files to the target Nodes by way of a file transfer. From there, a targeted Agent will be given access to the Behavior. + +A Behavior contains some action expected to be fulfilled by an Agent residing on a Node instance. + +Behaviors can be sent to connected Agents in a number of ways. + +**Using the Behavior Manager in SAGE App** - You can populate your existing Agents with Behaviors using the SAGE App. This is the manual way to configure your agent network with the proper Behaviors prior to executing your automation. + + 1) In the SAGE App, select the targeted Agent name and click :mod:`Add Behavior`. + 2) Select the Behavior name from the list of available Behaviors and click :mod:`Ok`. + 3) Enter the desired Behavior topic strings and click :mod:`Ok`. + +Assuming the Behavior file is in the proper sub-directory on the Server: + +**By a Controller Application** - You can add available behaviors to agents using a Controller Application, such as Robot Framework. This gives SAGE users the ability to control complex test scenarios, involving multiple nodes and agents, from a single controller entity. + + 1) In your robot file, use the :mod:`Add Behavior` keyword to populate a targeted Node and Agent name with the specified behavior. + + .. code-block:: bat + + Add Behavior nodeName1 newAgentName1 ExampleBehavior ExampleBheavior.jar Topic1 Topic2 + + +**Through the execution of a Behavior** - Agents have the ability configure other agent entities. This is a dynamic way to build your agent network to be more robust. This unique SAGE capability enables agents to send behaviors to other agents. + + 1) In your Behavior file, use the :mod:`addBehavior` method to populate a targeted Node and Agent with the specified behavior. + + .. code-block:: bat + + addBehavior("nodeName1", "newAgentName1", "ExampleBehavior", "ExampleBheavior.jar", "Topic1", "Topic2"); diff --git a/docs/_build/html/_sources/base_class_methods.rst.txt b/docs/_build/html/_sources/base_class_methods.rst.txt new file mode 100644 index 0000000..dcdb3c9 --- /dev/null +++ b/docs/_build/html/_sources/base_class_methods.rst.txt @@ -0,0 +1,544 @@ +Base Class - SAGE Behavior Methods +================================================================ + +The SAGE Behavior base class provides a number of powerful methods that allow Agents to communicate with other Agents, create and remove Agents, add and remove Behaviors from Agents, activate and deactivate Agents, and manage their Agent's state space. + +This capability in SAGE supports the idea of meta-agents that can reason about their current environment and create other Agents based on that reasoning. + + +.. _addBehavior-label: + +addBehavior ++++++++++++++++++++++++++++++++++++ + +This method enables SAGE Agents to populate other SAGE Agents with new Behaviors. + +- **nodeName** [string] + This is the name of a SAGE Node where the target Agent exists. + +- **agentName** [string] + This is the name of the SAGE Agent that will receive the new Behavior. + +- **behaviorName** [string] + This is the name that was assigned to the SAGE Behavior by its developer. + +- **module** [string] + This is the file name of the module containing the Behavior to be added. Depending on the language the Behavior was written in, this could be a Java .jar file, a Python .egg file, or a native dynamic load library (.dll or .so). + +- **topics** [string vector] + The topic vector specifies the set of topic names that the new Behavior will be interested in. Messages sent to the Behavior's Agent will only be routed to this new Behavior if the topic specified in the message matches one of the topic names in this vector. Behaviors that don’t specify a topic list receive all message irrespective of the topic the message specifies. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + void addBehavior(std::string nodeName, std::string agentName, std::string behaviorName, std::string module, std::vector topics); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public void addBehavior(String nodeName, String agentName, String behaviorName, String module, ArrayList topics) + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def addBehavior(self, nodeName, agentName, behaviorName, module_, topics) + + +.. _createAgent-label: + +createAgent ++++++++++++++++++++++++++++++++++++ + +This method enables SAGE Agents to create other SAGE Agents through their Behaviors. New Agents can be created on an Agent's local Node or a remote Node. + +- **nodeName** [string] + This is the name of a SAGE Node where the new Agent will be created. + +- **agentName** [string] + This is will be the name assigned to the new SAGE Agent. Agent names must be unique within the Node that contains them. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + void createAgent(std::string nodeName, std::string agentName); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public void createAgent(String nodeName, String agentName) + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def createAgent(self, nodeName, agentName) + +createState ++++++++++++++++++++++++++++++++++++ + +This method enables Behaviors to create a new, named state in its Agent's state space. State names must be unique so this method returns false if a state with the specified name already exists. + +- **name** [string] + This is the name of the new state to be added to state space. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool createState(std::string name); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public Boolean createState(String name) + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def createState(self, name) + +getState ++++++++++++++++++++++++++++++++++++ + +This method returns the value of a named state in an Agent's state space. The method throws an exception if the specified state name is not found. The state value is returned as a generic value. + +- **name** [string] + This is the name of the state whose value will be returned. + +In C++, the value is returned as a boost::variant that can contain long, double, or std::string types. The boost::variant which() method can be used to determine the type held. The which() method returns the 0-based index of the type currently held by the boost::variant. In SAGE, a value of 0 is a long, a value of 1 is a double, and a value of 2 is a std::string. + +To retreive the actual value of the boost::variant, use the boost::get(value) function template. For a long value use boost::get(value), for a double value use boost::get(value), and for a std::string value use boost::get(value). + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + sageframework::StateValueType getState(std::string name); + +In Java the value is returned as a generic Object. Java's getClass() method can be called on the Object to discover its type. The object can then be cast to the appropriate type to retreive its value. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public Object getState(String name) throws Exception + +In Python, the type(value) function returns the type of a variable. Python variables are dynamically typed so the value returned from the getState can be assigned to Python variable. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def getState(self, name) + + +getStateNames ++++++++++++++++++++++++++++++++++++ + +This method returns a vector of all the state names that currently exist in an Agent's state space. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + std::vector getStateNames(); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public Set getStateNames() + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def getStateNames(self) + +removeAgent ++++++++++++++++++++++++++++++++++++ + +This method enables SAGE Agents to remove other SAGE Agents through their Behaviors. Agents can be removed from an Agent's local Node or a remote Node. + +- **nodeName** [string] + This is the name of a SAGE Node where the target Agent exists. + +- **agentName** [string] + This is the name of the SAGE Agent that is removed. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + void removeAgent(std::string nodeName, std::string agentName); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public void removeAgent(String nodeName, String agentName) + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def removeAgent(self, nodeName, agentName) + + + + +removeBehavior ++++++++++++++++++++++++++++++++++++ + +This method enables SAGE Agents to remove existing Behaviors from other Agents. + +- **nodeName** [string] + This is the name of a SAGE Node where the target Agent exists. + +- **agentName** [string] + This is the name of the SAGE Agent that will have its Behavior removed. + +- **behaviorName** [string] + This is the name of the Behavior that will be removed. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + void removeBehavior(std::string nodeName, std::string agentName, std::string behaviorName); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public void removeBehavior(String nodeName, String agentName, String behaviorName) + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def removeBehavior(self, nodeName, agentName, behaviorName) + +removeState ++++++++++++++++++++++++++++++++++++ + +This method enables Behaviors to remove a named state from its Agent's state space. If the specified state name is not found, this method returns false. + +- **name** [string] + This is the name of the state to be removed from state space. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool removeState(std::string name); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public Boolean removeState(String name) + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def removeState(self, name) + + +.. _setAgentActive-label: + +setAgentActive ++++++++++++++++++++++++++++++++++++ + +This method enables SAGE Agents to activate and deactivate other SAGE Agents. Agents are created in an inactive state. Activating an inactive agents causes the :mod:`setUp()` methods of its Behaviors to be called and its :mod:`action()` and :mod:`message()` methods to be invoked based on the properties of the Agent and in response to incoming messages. Deactivating an active Agent causes the :mod:`tearDown()` method of its Behaviors to be called and the Agent then becomes dormant. + +- **nodeName** [string] + This is the name of a SAGE Node where the target Agent exists. + +- **agentName** [string] + This is the name of the SAGE Agent that will be activated or deactivated. + +- **isActive** [boolean] + This is a flag indicating if an Agent is to be activated (true) or deactivated (false). + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + void setAgentActive(std::string nodeName, std::string agentName, bool isActive); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public void setAgentActive(String nodeName, String agentName, boolean isActive) + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def setAgentActive(self, nodeName, agentName, isActive) + + +sendFile ++++++++++++++++++++++++++++++++++++ + +This method transmits a file to the SAGE Server. This capability is useful for sending auxiliary data or arbitrary files to a centralized location. Files transmitted to a SAGE Server running on the Windows operating system are placed in the sage\\downloads subfolder of the ProgramData folder (usually ``C:\ProgramData\SAGE\downloads``). + + +- **filePath** [string] + This is a fully qualified path to the file. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + void sendFile(std::string filePath); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public void sendFile(String filePath); + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def sendFile(self, filePath) + + +sendMessage ++++++++++++++++++++++++++++++++++++ + +The sendMessage method can be called by Behaviors to communicate with other Agents in the SAGE Agent network. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + void sendMessage(const sageframework::Message& message) + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public void sendMessage(Message message) + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def sendMessage(self, message) + + + +setState ++++++++++++++++++++++++++++++++++++ + +This method sets the value of named state in an Agent's state space. The method returns false if the state name is not found. +In C++ setState is a templated function that is instantiated for values of type long, double, and std::string. It can be called with values that are one of those three types. + +- **name** [string] + This is the name of the state whose value will be modified. + +- **value** [long, double, or std::string] + This is the new value that the state will take on. Valid values must of type long, double, or std::string. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + template bool setState(std::string, T value); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public Boolean setState(String name, Object value) + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def setState(self, name, value) \ No newline at end of file diff --git a/docs/_build/html/_sources/building_an_agent_network.rst.txt b/docs/_build/html/_sources/building_an_agent_network.rst.txt new file mode 100644 index 0000000..8d89a4e --- /dev/null +++ b/docs/_build/html/_sources/building_an_agent_network.rst.txt @@ -0,0 +1,31 @@ +Building an Agent Network +=========================================================== + +You can start to build out an agent network once you have established a connection between your SAGE Server and Node components. + +Agent entities can be created within any active Node using the SAGE App, a Controller Application, or within a Behavior. + +**SAGE App** - You can populate your existing Nodes with agents using the SAGE App. This is the manual way to configure your agent network with the proper Behaviors prior to executing your automation. + + 1) In the SAGE App, select the targeted Node name and click :mod:`Create Agent`. + 2) Type in a name for your agent and click the :mod:`OK` button. + +**Controller Application** - You can create agents using a Controller Application, such as Robot Framework. This method is a fast way to generate a large number of agents across any active Nodes. + + 1) In your robot file, connect the controller to the Server by using the keywords :mod:`Start Sage` and :mod:`Connect to Sage Runtime`. + 2) Use the :mod:`Create Agent` keyword to populate a targeted Node name with an expected Agent name. + + .. code-block:: bat + + Create Agent nodeName1 newAgentName1 + Create Agent nodeName1 newAgentName2 + Create Agent nodeName2 newAgentName1 + +**Behavior** - Agents have the ability to spawn and configure other agent entities. This is a dynamic way to build your agent network to be more robust. This unique SAGE capability is supported by initializing agents within your SAGE Behavior code. This enables agents to create other agents. + + 1) In your Behavior file, use the :mod:`CreateAgent` method to populate a targeted Node name with an expected Agent name. + + .. code-block:: bat + + createAgent("nodeName1", "newAgentName1"); + diff --git a/docs/_build/html/_sources/capturing_the_test_results.rst.txt b/docs/_build/html/_sources/capturing_the_test_results.rst.txt new file mode 100644 index 0000000..a909271 --- /dev/null +++ b/docs/_build/html/_sources/capturing_the_test_results.rst.txt @@ -0,0 +1,51 @@ +Capturing the Test Results +=============================== + +A Result object provides a reporting mechanism back to the server to indicate the results of the execution of a Behavior’s methods. + +The :mod:`m_logMessages` member is a vector of strings and is intended to provide a log of events that occurred during the execution of a Behavior. + +You can capture messages back to your Robot report by appending to this :mod:`m_logMessages` list: + +.. code-block:: java + + public boolean action(Result result) + { + System.out.println("Hello World from Action"); + result.m_logMessages.add("This is log message string3."); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + public boolean message(Message message, Result result) + { + System.out.println("Got message"); + result.m_logMessages.add("This is log message from message string1."); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + +As a result, your Robot log should read: + +.. code-block:: bat + + This is log message string3. + + This is log message from message string1. + + +While your console reads: + +.. code-block:: bat + + Hello World from Action + + Got message + +All execution logs and results are pushed back to the Server. Logs and results can be found on the **Server machine** in the following directories: + +.. code-block:: bat + + Logs directory: "C:\ProgramData\SAGE\logs" + + Results directory: "C:\ProgramData\SAGE\results" \ No newline at end of file diff --git a/docs/_build/html/_sources/changelog.rst.txt b/docs/_build/html/_sources/changelog.rst.txt new file mode 100644 index 0000000..63b5160 --- /dev/null +++ b/docs/_build/html/_sources/changelog.rst.txt @@ -0,0 +1,235 @@ +.. _`view-changelog`: + +Changelog +=========================== +**SAGE 3.0.3b** + +- This is a beta release. For access to the software email us at sageframework@nrl.navy.mil + +Release date: 2024-02-20 + +Core and Builtins + + - Both SAGE Node and Server are containerized + - Added Node Manager app to manage containerized and native instances of SAGE Node + - Added support for SAGE clusters. SAGE Servers running on remote machines can now discover each other and exchange agent messages + - Node and Server authentication. Nodes and Server instances can optionally use SSH-based authentication to encrypt their communications as well as to perform authentication + - Many UI enhancements + +**SAGE 2.0.34** + +Release date: 2021-05-20 + +Core and Builtins + + - Issue #56: Fixed bug that would allow Robot tests to continue if Behavior file was not found + - Issue #55: Fixed java memory leak in SAGE Node code + + +**SAGE 2.0.32** + +Release date: 2020-12-04 + +Core and Builtins + + - Issue #54: Improved error messages when using Robot. + - New server option to not print or log regular Sage messages. Does not affect warnings, errors or exceptions. + - Issue #53: Improved Node performance when processing a high volume of messages. + +Server Application + + - New server option to not print or log regular Sage messages by selecting the 'Quiet Mode' box in Server Settings. Does not affect warnings, errors or exceptions. + - Sage Server App now has the capability to show Agents' State Space. + +**SAGE 2.0.28** + +Release date: 2019-12-09 + +Core and Builtins + + - Issue #52: Fixed bug in periodic actions that occurred when the period specified is very small. This could lead to a race condition. + +**SAGE 2.0.24** + +Release date: 2019-08-05 + +Core and Builtins + + - Issue #51: Fixed bug, Java behaviors within JAR files that include supporting libraries could throw a duplicate class exception due to how Java loads dependencies. + +Server Application + + - Some UI enhancements. + - Bug fixes. + + +**SAGE 2.0.22** + +Release date: 2019-06-11 + +Core and Builtins + + - Issue #50: Fixed bug, under some conditions it was possible to get the Server to hang if you were trying to stop it but it was also waiting for a Result. + - Issue #49: Behavior members are now checked on each run of the scheduler. That way action and message methods can change period, execution type, delay, and trigger message at runtime. + - Issue #48: The environment variable SAGE_HOME has been replaced with SAGE_SERVER_HOME and SAGE_NODE_HOME. + - Issue #47: Better error checking to make sure multiple Agents on the same Node can't use different versions of a Behavior (Note: they will use different instances). + - Issue #46: Behaviors will now only be sent from the Server to the Node if the Node does not already have the latest version. + - Issue #45: Better information and error reporting from Nodes back to the Server. + - Issue #44: Fixed bug where under certain conditions a Node that was shut down on purpose would show an error message. + - Issue #43: For Java, Sage no longer uses the system CLASSPATH environment variable and instead uses SAGE_CLASSPATH. + - Issue #42: All Java behaviors now must be in jars and are internally loaded by a custom class loader. + - Issue #41: Fixed a bug where a TimedCyclical behavior could drift over time. + - Issue #40: Fixed an issue where a new version of a Behavior was not properly replacing the old version in a Node. + - Issue #39: Added Keywords to Sage Robot Keywords to allow access to individual parts of a Result object, for example "Get Result Behavior Name". + +Server Application + + - Light and dark color scheme enhancements. + - Behavior Manager now a non-modal dialog window. + - Added application settings for specifying which non-modal dialog windows stay on top of the main form window. + - Added double-click event handling for agent tree view nodes. + - Bug fixes. + + +**SAGE 1.2.18** + +Release date: 2018-10-08 + +Core and Builtins + + - Issue #38: Fixed message broadcasting bug. + - Issue #37: Added JSON based introspection for getting detailed Agent state. + - Issue #36: Fixed introspection bug. + - Issue #35: Added new scheduling mechanism that allows users to control the precision of the Node scheduler to control the CPU usage of SageNodeConsole. + +Server Application + + - Improved UI interactions for selecting Nodes, Agents, and Behaviors. + - Improved Network graph view layout. + - Added zoom control to Network graph view. + - Added application settings for controlling Node scheduler precision. + - Added light and dark theme selections. + - Fixed core bugs. + + +**SAGE 1.1.14** + +Release date: 2017-09-28 + +Core and Builtins + + - Issue #34: User's CLASSPATH is now appended to the runtime CLASSPATH. + - Issue #33: Added new SAGE Robot keyword Clear Results. + - Issue #32: BehaviorModule class now only returns a single behavior instead of a vector of behaviors. This addresses potential memory corruption due to cross DLL allocation/deallocation. + - Issue #31: Fixed bug that would cause JVM to unexpectedly crash. + - Issue #30: Added server methods to load and save agent networks so that clients don't have to instantiate SAGE internal classes. + - Issue #29: Fixed bug that would cause the loss of Result objects. + - Issue #28: Fixed crash of Robot caused by Result objects being corrupted. + - Issue #27: Fixed GDI resource issue. + - Issue #26: Fixed issue with Behavior files not being overwritten on Node machine if Server contained newer version of file. + - Issue #25: Fixed problem with SAGE Server memory leak caused by the server running for very long periods of time. + - Issue #24: Fixed memory leak in SAGE Node code. + - Issue #23: Fixed issue where Node would not reconnect to SAGE Server after stopping then starting Server. + - Issue #22: Added support for sending files back to the server. Base class functionality now includes sendFile method. + - Issue #21: Added support for persistent networks. Network settings can be stored as SAGE extension files for save/load capability. + +Server Application + + - View SAGE User Guide from Help window. + - Add Network graph view. + - Integrate Import and Export network settings. + - Add "Activate All Agents", " Deactiviate All Agents", and "Remove All Agents" buttons. + - Update layout and icons. + + +**SAGE 1.0.12** + +Release date: 2017-06-27 + +Core and Builtins + + - Issue #20: Fixed problem with SAGE ServerApp not allowing behaviors to be overwritten in the Behavior Manager. + - Issue #19: Fixed issue in SAGE ServerApp where behaviors would not show up in the tree view until the one of the behaviors' methods is called. + - Issue #18: Fixed problem where sending a message back to the sender in the message() method would crash SAGE. + - Issue #17: Added support for packaged behaviors. Behaviors and supporting class files may now be packaged into JAR and EGG files. + +Server Application + + - Items respond immediately to mouse-clicks when not in focus. + - Update layout and icons. + - Add bi-directional object selection. + +Documentation + + - Add Robot Framework background. + - Update SAGE Server Application. + + +**SAGE 1.0.11** + +Release date: 2017-03-07 + +Core and Builtins + + - Issue #16: JVM path automatically appended to the system environment PATH variable. + - Issue #15: Modified Namespaces for SageBehaviorInterface (both Java and Python module) to nrl.sage.BehaviorInterface, SageRemoteInterface to nrl.sage.BehaviorInterface, and SageLocalInterface to nrl.sage.BehaviorInterface. + - Issue #14: Linux SageNode rpm now correctly sets folder permissions in /etc/sage. + - Issue #13: Fixed problem with running robot files in SageServerApp when the user account does not have administrator privileges. + - Issue #12: Added a package name to the SageRemoteInterface.jar library. Java applications using that jar must import sageremoteinterface.* + - Issue #11: Added support that enables SAGE to be installed and operate properly on machines that don't have Java and/or Python installed. (Windows version only) + - Issue #10: Fixed problem with importing Java behaviors using the behavior manager in SageServerApp. + + +**SAGE 1.0.10** + +Release date: 2016-12-15 + +Core and Builtins + + - Issue #9: Improved Robot error reporting to include more informative messages. + - Issue #8: Fixed issue where the SageServer was not updated when an agent was removed by another agent that resides in the same Node. + + +**SAGE 1.0.9** + +Release date: 2016-10-31 + +Core and Builtins + + - Issue #7: Added source node and source agent fields to messages sent to Behaviors. + - Issue #6: Run Step and Report Result now throw an exception on result = "failure". + - Issue #5: Routines in SageRobotKeywords.java now return a boolean value. + + +**SAGE 1.0.8** + +Release date: 2016-10-07 + +Documentation + + - Update API Reference section with C++ Behavior file example. + +Library + + - Update Boost to 1.61.0. + - Removed Pluma dependencies. + +**SAGE 1.0.7** + +Release date: 2016-09-28 + + +Core and Builtins + + - Issue #4: Added support for asynchronous/multi-threaded calls. + - Issue #3: Wait For Result SageRobotKeyword now takes an additional argument that indicates which method to wait on to generate a result. + - Issue #2: The Behavior methods setUp() and tearDown() now are called with a Result parameter. + - Issue #1: Fixed bug that continued Behavior process after internal error occurred in Behavior methods setUp(), action(), message(), or tearDown(). + + +Server Application + + - Add new Options menu. + - Add new Options and Server tool strips. + - Add context sensitive interaction between the AgentTreeView and the menu/toolstrip tools. + diff --git a/docs/_build/html/_sources/connecting_a_node_to_the_server.rst.txt b/docs/_build/html/_sources/connecting_a_node_to_the_server.rst.txt new file mode 100644 index 0000000..326cbf5 --- /dev/null +++ b/docs/_build/html/_sources/connecting_a_node_to_the_server.rst.txt @@ -0,0 +1,28 @@ +Connecting a Node to the Server +===================================================== + +**Initialize node** + +On a :mod:`Windows` command prompt enter the following command: + + .. code-block:: bat + + SageNodeConsole_x64.exe nodeName {server_IP_address} {port_number} *{scheduler_mode} + +On a :mod:`Linux` terminal enter the following command: + + .. code-block:: bat + + SageNodeConsole nodeName {server_IP_address} {port_number} *{scheduler_mode} + +*scheduler_mode* is optional and accepted mode values depend of the current CPU load: + + - "high" - Scheduler runs with sub millisecond accuracy and yields the processor between runs of the scheduler. Running in high mode is not recommended for battery powered devices. + - "medium" (Default) - Scheduler runs every 1-2 milliseconds. + - "low" - Scheduler runs every 15 milliseconds. + + + +To verify if a SAGE Node is operational, check the prompt window and confirm that the following text is displayed + ``Connected to SAGE runtime using ip address {server_IP_address}:{port_number}``. + diff --git a/docs/_build/html/_sources/contact_us.rst.txt b/docs/_build/html/_sources/contact_us.rst.txt new file mode 100644 index 0000000..2fe6c1a --- /dev/null +++ b/docs/_build/html/_sources/contact_us.rst.txt @@ -0,0 +1,7 @@ +Contact us +=========================== +**Email** + +sageframework@nrl.navy.mil + + diff --git a/docs/_build/html/_sources/creating_a_test_case_using_robot_framework.rst.txt b/docs/_build/html/_sources/creating_a_test_case_using_robot_framework.rst.txt new file mode 100644 index 0000000..80f13c9 --- /dev/null +++ b/docs/_build/html/_sources/creating_a_test_case_using_robot_framework.rst.txt @@ -0,0 +1,152 @@ +Creating A Test Case Using Robot Framework - Controller Application +==================================================================== + +A Controller in the SAGE Framework is an external application that interacts with the SAGE Server. + +This component is optional. However, it is highly recommended for users using SAGE for test automation to use a Controller to interact with your tests. It provides greater visibility by enabling report generation and step-by-step test case building. + +By default, SAGE Framework supports native Robot Framework integration as a SAGE controller mechanism. + +By remotely connecting Robot Framework to an running SAGE Server instance, you can manage a network of Agents in a single Robot file using Keyword-based testing. + +For users in test automation, controlling your agent network via Robot Framework provides the following benefits: + + - You can construct an entire test case in a single file. + - Robot Framework prints a test report with each step producing a result. + - You can quickly create several independent agent networks for multiple test cases. + - All tests are stored and ran from a single server machine. + - You can run multiple Robot files sequentially. + +If either of these benefits are not fitting for your automation needs, then you may not require the use of a controller mechanism. Instead, continue using the Server and Node only. + +Keywords, such as ``Start SAGE``, ``Connect To SAGE Runtime``, ``Create Agent``, ``Add Behavior``, and ``Activate Agent`` are used to construct an agent network. + +.. code-block:: bat + + **Test Cases** + This is an Example Test + Start SAGE + Connect To SAGE Runtime {server_IP_address} {port_number} + Create Agent nodeName1 agentName1 + Add Behavior nodeName1 agentName1 {behaviorName} {behaviorModule} topic + Activate Agent nodeName1 agentName1 + +While keywords, such as ``Remove Agent`` and ``Deactivate Agent``, can be used to de-construct your network. + +.. code-block:: bat + + **Test Cases** + This is an Example Test + Start SAGE + Connect To SAGE Runtime {server_IP_address} {port_number} + Create Agent nodeName1 agentName1 + Add Behavior nodeName1 agentName1 {behaviorName} {behaviorModule} topic + Activate Agent nodeName1 agentName1 + Deactivate Agent nodeName1 agentName1 + Remove Agent nodeName1 agentName1 + + +Using keywords, such as ``Send Message`` and ``Run Step`` allows the Server to send a message to a targeted Agent. + +.. code-block:: bat + + **Test Cases** + This is an Example Test + Start SAGE + Connect To SAGE Runtime {server_IP_address} {port_number} + Create Agent nodeName1 agentName1 + Add Behavior nodeName1 agentName1 {behaviorName} {behaviorModule} topic + Activate Agent nodeName1 agentName1 + Send Message nodeName1 agentName1 Topic1 Hello + Deactivate Agent nodeName1 agentName1 + Remove Agent nodeName1 agentName1 + +Depending on the Behavior construction, an agent will perform either **reactively** in response to an incoming message or **proactively** upon the receipt of a specific trigger message or at activation. + + +Here's an example constructed test case: + +.. code-block:: bat + + This is an Example Test + Start SAGE + Connect To SAGE Runtime 121.0.0.1 50001 + Create Agent recipientNode recipientAgent + Add Behavior recipientNode recipientAgent ExampleBehavior ExampleBehavior.jar Topic1 + Activate Agent recipientNode recipientAgent + Send Message recipientNode recipientAgent Topic1 Hello + Deactivate Agent recipientNode recipientAgent + Remove Agent recipientNode recipientAgent + + +Looking at the Java code for ExampleBehavior file: + +.. code-block:: java + + public ExampleBehavior() + { + m_executionType = ExecutionType.NoExecution; + m_description = "Example Behavior"; + m_name = "ExampleBehavior"; + } + public boolean setUp(Result result) + { + System.out.println("begin"); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + public boolean action(Result result) + { + System.out.println("Hello World from Action"); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + public boolean message(Message message, Result result) + { + System.out.println("Got message "+ message.m_message + " on topic " + message.m_topic); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + public boolean tearDown(Result result) + { + System.out.println("end"); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + +If all goes well, you should see the following results from your executed test case: + +.. code-block:: bat + + begin + Got message Hello on topic Topic1 + end + +This is because, the :mod:`Send Message` Keyword points to the Behavior associated with Topic1 (ExampleBehavior). Knowing this, the Server sends message "Hello" to the recipient Agent (recipientAgent) using that Behavior. + +If you were to make the following change to :mod:`Send Message`: + +.. code-block:: bat + + This is an Example Test + Start SAGE + Connect To SAGE Runtime 121.0.0.1 50001 + Create Agent recipientNode recipientAgent + Add Behavior recipientNode recipientAgent ExampleBehavior ExampleBehavior.jar Topic1 + Activate Agent recipientNode recipientAgent + Send Message recipientNode recipientAgent Topic10000 Hello + Deactivate Agent recipientNode recipientAgent + Remove Agent recipientNode recipientAgent + +You would expect the following results from your executed test case: + +.. code-block:: bat + + begin + end + +This is due to the message not being propagated to any Behavior, as no Behavior was added that is associated with Topic10000. + diff --git a/docs/_build/html/_sources/creating_your_own_controller_application.rst.txt b/docs/_build/html/_sources/creating_your_own_controller_application.rst.txt new file mode 100644 index 0000000..7576b20 --- /dev/null +++ b/docs/_build/html/_sources/creating_your_own_controller_application.rst.txt @@ -0,0 +1,595 @@ +Creating Your Own Controller Application +====================================================================== + +A Controller in the SAGE framework is an application that interacts with the SAGE Server to create and manage a network of Agents. SAGE Controller applications +are external applications that remotely connect to an instance of a SAGE Server running in either a console application (ex. SageServerConsole_x64.exe) or +in the SageServerApplication. + +The SAGE SDK provides both C++ and Java bindings for creating Controller applications. The SageRemoteInterface class provides an interface for creating +a remote connection to an instance of the SAGE Server and for creating and managing agents. + +Using the SageRemoteInterface to create and manage an Agent network, a Control application performs the following steps: + +1) Create an instance of the SageRemoteInterface class. +2) Connect to the SAGE Server by providing an IP address and port number. +3) Create and manage the Agent network. +4) Synchronize events. +5) Retrieve results. +6) Disconnect from the SAGE server. +7) Destroy the SageRemoteInterface object. + +The SageRemoteInterface class provides a number of methods to interface with Controller applications. + +addBehavior ++++++++++++++++++++++++++++++++++++ + +This method adds a new Behavior to a SAGE Agent. Behaviors are units of execution that define how an Agent acts either due to a deterministic execution pattern, or in response to an incoming message. This method allows the caller to specify an optional set of topics that act as a message filter for the Agent. If a topic set is specified for a Behavior, then only incoming messages that specify one of those topics will be passed through to that Behavior. If no topic set is specified, then all messages are passed to the Behavior. This method returns a boolean value indicating whether or not the Behavior was successfully added. + +- **nodeName** [string] + This is the name of the SAGE Node in which the Agent resides. + +- **agentName** [string] + This is the name of the Agent. + +- **behaviorName** [string] + This is the name that was assigned to the SAGE Behavior by its developer. + +- **module** [string] + This is the file name of the module containing the Behavior to be added. Depending on the language the Behavior was written in, this could be a Java .class file, a Python .py file, or a native dynamic load library (.dll or .so). + +- **topics** [string vector] + The topic vector specifies the set of topic names that the new Behavior will be interested in. Messages sent to the Behavior's Agent will only be routed to this new Behavior if the topic specified in the message matches one of the topic names in this vector. Note that messages that do not specify a topic are sent to all Behaviors and conversely Behaviors that don't specify a topic list receive all messages irrespective of the topic the message specifies. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool addBehavior(std::string nodeName, std::string agentName, std::string behaviorName, std::string module, std::vector topics); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean addBehavior(String nodeName, String agentName, String behaviorName, String module, StringVector topics); + + +connect ++++++++++++++++++++++++++++++++++++ + +This method establishes a connection to a running SAGE Server either on the local machine or an a remote machine. It returns a boolean value indicating if the connection was +successfully established. + +- **serverIPAddress** [string] + This is the IP address of the machine where the SAGE Server is running. + +- **portNumber** [integer] + This is the port number that the SAGE Server is using to accept new connection. The port number is specified when the server is started. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool connect(std::string serverIPAddress, int portNumber); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean connect(String serverIPAddress, int portNumber); + +clearExecutionResults ++++++++++++++++++++++++++++++++++++ + +This method clears the set of Result objects reported to the SAGE Server. Control Applications can use this method after retrieving Result objects using getExecutionResults to avoid duplicates. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + void clearExecutionResults(); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public void clearExecutionResults(); + + +createAgent ++++++++++++++++++++++++++++++++++++ + +This method creates a SAGE Agent in the specified SAGE Node. The Node is identified by the name that was given when is was created. Node names must be unique across Agent networks. +The Agent is created in an inactive state and must be activated before it will initiate any of its Behaviors. This method returns a boolean value indicating whether or not the +Agent was created. + +- **nodeName** [string] + This is the name of the SAGE Node in which the Agent will be created. + +- **agentName** [string] + This is the name that will be assigned to the new SAGE Agent. Agent names must be unique within a SAGE Node. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool createAgent(std::string nodeName, std::string agentName); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean createAgent(String nodeName, String agentName); + + +disconnect ++++++++++++++++++++++++++++++++++++ + +This method ends a connection to a running SAGE Server. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + void disconnect(); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public void disconnect(); + +getAgentNames ++++++++++++++++++++++++++++++++++++ + +This method returns the names of all the SAGE Agents residing in the specified Node. + +- **nodeName** [string] + This is the name of the SAGE Node whose Agent names are to be returned. + +- **agentNames** [vector of strings] + This is a vector of strings containing SAGE Agent names. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool getAgentNames(std::string nodeName, std::vector& agentNames); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean getAgentNames(String nodeName, StringVector agentNames); + + StringVector is a Java class that provides a get(int i) method for retrieving the Agent name at index i. + +getExecutionResults ++++++++++++++++++++++++++++++++++++ + +This method returns all the Result objects that have been reported to the SAGE Server at the time of the call. This method does not clear the set of Result objects. Subsequent calls to this method will return the cumulative Result objects until the clearExecutionResults method is called. + +- **results** [vector of Result objects] + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + void getExecutionResults(std::vector& results); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public void getExecutionResults(ResultVector results); + + ResultVector is a Java class that provides a get(int i) method for retrieving the Result at index i. + + +The Result class enables Behaviors to report the results of the execution of either a :mod:`action()` method or a :mod:`message()` method. It consists of the following members: + +- **m_logMessages** while the container type varies across languages, the m_logMessages member is a vector of strings and should is intended to provide a log of events that occurred during the execution of a Behavior. + +- **m_exception** if the execution of code in the :mod:`action()` method or a :mod:`message()` methods generates an exception, the m_exception string should contain text describing the cause of the exception. + +- **m_executionResult** this member consists of an enumeration of type ExecutionResultType. It can have one of three values: + - ``CompletionSuccess`` - the method completed execution successfully + - ``CompletionFailure`` - the method completed execution but failed + - ``ExceptionThrown`` - code in the method caused an exception to be thrown. It is highly recommended that Behavior developers execute any code that can potentially generate exceptions withing a try - catch statement. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + std::vector m_logMessages; + std::string m_exception; + ExecutionResultType m_executionResult; + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public ArrayList m_logMessages = new ArrayList(); + public String m_exception = ""; + public ExecutionResultType m_executionResult = ExecutionResultType.CompletionSuccess; + + + + +getNodeNames ++++++++++++++++++++++++++++++++++++ + +This method returns the names of all SAGE Nodes connected to this SAGE Server. + +- **nodeNames** [vector of strings] + This is a vector of strings containing SAGE Node names. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + void getNodeNames(std::vector& nodeNames); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public void getNodeNames(StringVector nodeNames); + + StringVector is a Java class that provides a get(int i) method for retrieving the Node name at index i. + + +sendFile ++++++++++++++++++++++++++++++++++++ + +This method transmits a file to a SAGE Node. This capability is useful for sending auxiliary data or executable library files needed by Behaviors. Files transmitted to a SAGE Node running on the Windows operating system are placed in the sage\\data subfolder of the ProgramData folder (usually ``C:\ProgramData\SAGE\data``). On the Linux operating system, files are placed in the ``/etc/sage/data`` folder. + +- **nodeName** [string] + This is the name of a SAGE Node where the file will be sent. + +- **filePath** [string] + This is a fully qualified path to the file. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool sendFile(std::string nodeName, std::string filePath); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean sendFile(String nodeName, String filePath); + +sendMessage ++++++++++++++++++++++++++++++++++++ + +The sendMessage method enables the Control Application to send messages to Agents. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool sendMessage(const sageframework::Message& message) + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean sendMessage(Message message); + + +The Message class provides the necessary mechanism to specify a message recipient and the message content. + +- **m_targetNodeName** [string] + This is the name of the SAGE Node that is the recipient of this message. If left empty, the message is sent to all the Nodes in the SAGE network. + +- **m_targetAgentName** [string] + This is the name of the SAGE Agent that is the recipient of this message. If left empty, the message is sent to all the Agents in the specified SAGE Node. + +- **m_topic** [string] + If specified, a topic name acts to direct a message to only those Behaviors that have that topic included in their topics list. This provides a filtering mechanism so that messages are only sent to those Behaviors interested in them. + +- **m_message** [string] + This is an arbitrary, application defined string that specifies what the message is. + +- **m_data** [string vector] + This string vector allows the message sender to include an arbitrary number of data items with the message. The content of that data is application defined. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + class Message + { + public: + std::string m_targetNodeName; + std::string m_targetAgentName; + std::string m_topic; + std::string m_message; + std::vector m_data; + } + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public class Message + { + public String m_targetNodeName; + public String m_targetAgentName; + public String m_topic; + public String m_message; + public ArrayList m_data = new ArrayList(); + } + + +setAgentActive ++++++++++++++++++++++++++++++++++++ + +This method sets the active state of an SAGE Agent. Agents are created in an inactive state so that Agent Behaviors are not eligible for execution. This allows the Control Application to populate the Agent with Behaviors before any Behaviors execute. This method returns a boolean value indicating whether or not the Agent state was set. + +- **nodeName** [string] + This is the name of the SAGE Node in which the Agent resides. + +- **agentName** [string] + This is the name of the Agent. + +- **isActive** [boolean] + This is a boolean flag specifying whether the Agent state should be active (true), or inactive (false). + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool setAgentActive(std::string nodeName, std::string agentName, bool isActive); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean setAgentActive(String nodeName, String agentName, boolean isActive); + + +removeAgent ++++++++++++++++++++++++++++++++++++ + +This method removes a SAGE Agent from the specified SAGE Node. The Node is identified by the name that was given when is was created. It is good practice for Control applications to remove any Agents they created before exiting. This method returns a boolean value indicating whether or not the Agent was removed. + +- **nodeName** [string] + This is the name of the SAGE Node in which the Agent will be removed. + +- **agentName** [string] + This is the name of the Agent to remove. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool removeAgent(std::string nodeName, std::string agentName); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean removeAgent(String nodeName, String agentName); + + + +removeBehavior ++++++++++++++++++++++++++++++++++++ + +This method removes an existing Behavior from an Agent. This will cause the Behavior's :mod:`tearDown()` method to be invoked. + +- **nodeName** [string] + This is the name of a SAGE Node where the target Agent exists. + +- **agentName** [string] + This is the name of the SAGE Agent that will have its Behavior removed. + +- **behaviorName** [string] + This is the name of the Behavior that will be removed. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + void removeBehavior(std::string nodeName, std::string agentName, std::string behaviorName); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public void removeBehavior(String nodeName, String agentName, String behaviorName) + + + +waitForResult ++++++++++++++++++++++++++++++++++++ + +This method causes the Control Application to block until a specified Behavior executes either its :mod:`action()` method or its :mod:`message()` method and generates a Result object. +This capability is useful for synchronizing the execution of the Control Application with events in the Agent network. + +- **nodeName** [string] + This is the name of a SAGE Node where the Agent resides. + +- **agentName** [string] + This is the name of the SAGE Agent that has the target Behavior. + +- **behaviorName** [string] + This is the name of the Behavior that generates the Result object. + +- **timeOut** [int] + This the maximum time, in milliseconds, that the Control Application will block waiting for the Result object. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool waitForResult(std::string nodeName, std::string agentName, std::string behaviorName, int timeOut); + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean waitForResult(String nodeName, String agentName, String behaviorName, int timeOut); \ No newline at end of file diff --git a/docs/_build/html/_sources/example.rst.txt b/docs/_build/html/_sources/example.rst.txt new file mode 100644 index 0000000..c755082 --- /dev/null +++ b/docs/_build/html/_sources/example.rst.txt @@ -0,0 +1,271 @@ +.. _examples-label: + +Example +================== + +Test case +---------------------------------------------------------------- + +**SenderReceiverTest.robot** + +Robot file that uses the SageRobotKeywords [Library] and contains one [Test Case] titled "Test Message Communications". + +.. code-block:: bat + + # "%JAVAHOME_X64%\bin\java.exe" -cp "%SAGE_CLASSPATH%" org.robotframework.RobotFramework SenderReceiverTest.robot + + *** Settings *** + Documentation Used to test communications across the Agent network. + ... Sets up SAGE Agents with their corresponding Behavior and activates them. + ... Waits until the Agents are done communicating to generate report. + + Library SageRobotKeywords + Test Setup Connect to SAGE Server + Test Teardown Log Results + + *** Test Cases *** + Test Message Communications + # Create Agents on existing Nodes + Create Agent NodeOne Agent1 + Create Agent NodeTwo Agent2 + + # Add Behaviors to Agents so that they can learn skill + Add Behavior NodeOne Agent1 SenderReceiverBehavior SenderReceiverBehavior.jar talking + Add Behavior NodeTwo Agent2 SenderReceiverBehavior SenderReceiverBehavior.jar talking + + # Activate Agents + Activate Agent NodeOne Agent1 + Activate Agent NodeTwo Agent2 + + # Wait until each Agent reports back to the Server upon completion + Wait For Result NodeOne Agent1 SenderReceiverBehavior teardown 100000 + Wait For Result NodeTwo Agent2 SenderReceiverBehavior teardown 100000 + + + *** Keywords *** + Connect to SAGE Server + Start Sage + Connect to Sage Runtime 127.0.0.1 50001 + + Log Results + # Gather results that have been logged + @{RESULTS} Get Results + + :FOR ${ELEMENT} IN @{RESULTS} + \ Report Result ${ELEMENT} + + # Clear results so that no results are cached + Clear Results + + +[Test Setup] includes running the Keyword named "Connect to SAGE Server", identified in the *Keywords* table which includes: + + - ``Start Sage`` + - ``Connect to Sage Runtime`` + +The [Test Case] involves dynamically constructing two Agent entities on separate connected Nodes. Both Agents are to learn the same Behavior. + +In order to add the Behavior to an Agent you must give the ``Add Behavior`` keyword the following arguments: + + - *nodeName* - refers to target Node. + - *agentName* - refers to target Agent. + - *behaviorName* - refers to the Behavior’s name (m_name) variable found within the Behavior's constructor. + - *behaviorModule* - refers to the Behavior filename. + - *topics* - allows you to add tags to Behaviors so that you can properly associate a message with a particular Behavior. + + +Incorporating the ``Wait For Result`` keyword ensures that Robot will not conclude prematurely. In this example, you wait until the teardown() method of each Agent returns the results of its execution before concluding the test. This enables the Server to wait until the Agents have finished communicating before generating a report. Otherwise, Robot will conclude the test after activating Agent2. + + +After the test has concluded, the [Test Teardown] execution will gather the logged events from the preceding steps, as well as clear those logs once captured. + + +**SenderReceiverBehavior.java** + +Behavior file that demonstrates the use of having both a reactive and proactive execution response. + +.. code-block:: java + + /* Use the following command line to build: + javac -cp "%SAGE_SERVER_HOME%"\SageJavaBehaviorInterface.jar SenderReceiverBehavior.java + + Create JAR file: + jar cf SenderReceiverBehavior.jar SenderReceiverBehavior.class + */ + + import nrl.sage.BehaviorInterface.*; + + public class SenderReceiverBehavior extends SageBehavior + { + int count; + String senderAgent; + String senderNode; + String receiptAgent; + String receiptNode; + + public SenderReceiverBehavior() + { + m_name = "SenderReceiverBehavior"; + m_description = "Periodically sends messages to other agents all while receiving messages"; + m_executionType = ExecutionType.TimedCyclical; + m_delay = 50; + m_period = 200; + } + + public boolean setUp(Result result) + { + count = 1; + result.m_executionResult = ExecutionResultType.NotSet; + return true; + } + + public boolean action(Result result) + { + try{ + // Using Agent state, retrieve the information of the Agent using this Behavior + senderAgent = (String)getState("agent"); + senderNode = (String)getState("node"); + + // Knowing who the sender agent is, store the intended agent recipient information + if (senderAgent.equals("Agent1")){ + receiptAgent = "Agent2"; + receiptNode = "NodeTwo"; + } + else { + receiptAgent = "Agent1"; + receiptNode = "NodeOne"; + } + + // Construct the message content to send. + Message messageToAgent = new Message(); + messageToAgent.m_message = "send" + " messageNo:" +Integer.toString(count); + messageToAgent.m_data.add(senderAgent); + messageToAgent.m_data.add(receiptAgent); + messageToAgent.m_targetNodeName = receiptNode; + messageToAgent.m_targetAgentName = receiptAgent; + messageToAgent.m_topic = "talking"; + sendMessage(messageToAgent); + + // Increase count to know how many messages have been sent + count++; + + System.out.println(senderAgent + " sent " + messageToAgent.m_message + " to " +receiptAgent); + } + catch (Exception e){ + result.m_exception = e.toString(); + result.m_executionResult = ExecutionResultType.ExceptionThrown; + } + + result.m_executionResult = ExecutionResultType.NotSet; + return true; + } + + public boolean message(Message message, Result result) + { + // Print the message content in the console + System.out.println(message.m_data.get(1) + " received " + message.m_message + " from " + message.m_data.get(0)); + + // Deactivate agents after 20 messages have been sent + if (count>20){ + setAgentActive(receiptNode, receiptAgent, false); + setAgentActive(senderNode, senderAgent, false); + } + + result.m_executionResult = ExecutionResultType.NotSet; + return true; + } + public boolean tearDown(Result result) + { + + System.out.println("Tearing down behavior " + m_name); + + // Log event + result.m_logMessages.add(senderAgent + " signing off. Goodbye!"); + + // Report back to the Server indicating a successful teardown + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + } + + + +The following indicates that the Agent will proactively respond at activation: + + - *m_executionType* has been set to TimedCyclical; + +Proactive responses invoke the action() method. In this example, the response is to construct and send a message to a fellow Agent after identifying the originating Agent. + +TimedCyclical execution type continuously invokes the action() method. This continuous calling of the action() method enables the Agent to send more than one message. + + +The message() method handles the Agents reactive response and is invoked by way of message. In this example, the Agent is assumed to receive messages that contain the following content: + + - *message.m_message* - contains a string. + - *message.m_data.get(0)* - contains the sender's name. + - *message.m_data.get(1)* - contains the receiver's name. + +Once the Agent has received 20 messages it will proceed to deactivate its fellow Agent, as well as itself. + +The tearDown() method will be invoked upon deactivation, signaling the Agent to report the result of the tearDown back to the Server. + + + +Running test +------------------------------------- + +On your ``Server`` machine, create a java file using the above Behavior code to create ``SenderReceiverBehavior.java``. Compile the code and place it into the Java Behavior sub-directory: + + .. code-block:: bat + + For Windows: C:\ProgramData\SAGE\behaviors\Java\SenderReceiverBehavior.jar + + For Linux: /etc/Sage/behaviors/Java/SenderReceiverBehavior.jar + + +Ensure that both the SAGE Server and SAGE Node were installed with Java support. In addition, ensure that the Behavior file has been placed in the correct directory *(C:\\ProgramData\\SAGE\\behaviors\\Java)* on the Server machine. If not yet done, add the Behavior file to the specified directory. + +Start the SAGE Server by opening the terminal and typing the command: + + .. code-block:: bat + + SageServerConsole_x64.exe 50001 + + +Create and connect a Node named ``NodeOne`` by typing: + + .. code-block:: bat + + SageNodeConsole_x64.exe NodeOne 127.0.0.1 50001 + +Create and connect a Node named ``NodeTwo`` by typing: + + .. code-block:: bat + + SageNodeConsole_x64.exe NodeTwo 127.0.0.1 50001 + + +Upon successful connection, you will be ready to run the test. + +Create your Robot test case using the above Robot Framework code to create ``SenderReceiverTest.robot``. + +Start the example by by typing: + + .. code-block:: bat + + java -cp "%SAGE_CLASSPATH%" org.robotframework.RobotFramework SenderReceiverTest.robot + + +.. _resultsdemo-label: + +Generated results +---------------------------------------------- + +A report and log HTML file are generated after running test. Report gives you an overview of the test execution by detailing viewable statistics including Pass/Fail ratios and elapsed times. Log details statistics from each step of the test execution, from keyword to keyword. It enables you to drill down on the specifics of the test in case of failure or otherwise `[*] `_. + +Expand the elements to find returned results for each step execution. For more information regarding report and log files, see `Robot Framework output documentation `_. + +This log is based on successfully running SenderReceiverTest.robot. + +.. figure:: _images/log_example.png \ No newline at end of file diff --git a/docs/_build/html/_sources/features.rst.txt b/docs/_build/html/_sources/features.rst.txt new file mode 100644 index 0000000..7df6d03 --- /dev/null +++ b/docs/_build/html/_sources/features.rst.txt @@ -0,0 +1,77 @@ +Features +===================================== + +.. container:: row + + .. container:: two-caption + + Multiple language support + + .. container:: two-text + + SAGE was designed to be both language and operating system agnostic. SAGE supports agent behaviors written in C++, Java, and Python. In most cases, new programming languages can be readily integrated. + + .. container:: two-caption + + .. figure:: _images/features_1.png + +.. container:: row + + .. container:: two-caption + + .. figure:: _images/features_2.png + + .. container:: two-caption + + Dynamic agent configuration + + .. container:: two-text + + Dynamically construct and deconstruct agents to introduce a greater level of system control. SAGE agents can create and populate other agents with behaviors based on current operational needs. These smart agents may evolve with the system under test and enable reasoning in changing contexts, flexible configurations, and increased agent awareness. + +.. container:: row + + .. container:: two-caption + + Testing distributed systems with SAGE + + .. container:: two-text + + SAGE provides a powerful framework for automated testing of distrubuted systems, such as SOA systems-of-systems. SAGE is not inherently a test automation technology. However, the ability to coordinate and synchonize agent activities across a distributed system under test has been used to create a test automation capability that integrates a hetrogenious set of automation technologies into a coherent test automation harness. The SAGE framework supports integration with `Robot Framework `_, a widely used and extensible test specification and automation technology. SAGE extends Robot Framework's capabilities to include support for building and configuring SAGE agent networks for test automation. This enables detailed test specification in Robot Framework that includes a specification of the agent network needed for an automated test. Test activies carried out by distributed agents are reported to the SAGE server providing a centralized reporting capability. These test results are used by Robot Framework to create a single report outlining test results across the distributed system. + + .. container:: two-caption + + .. figure:: _images/features_3.png + +.. container:: row + + .. container:: two-caption + + .. figure:: _images/features_4.png + + .. container:: two-caption + + Modular by design + + .. container:: two-text + + SAGE Framework permits easy language agnostic extensibility and enhancement to support the introduction of new systems and ad hoc test tools. Seamlessly combine, otherwise disconnected, third-party tools and libraries to easily extend functionality. + + +.. container:: row + + .. container:: two-caption + + Persistent network capability + + .. container:: two-text + + Store network state to facilitate the automation of large scale systems. Speed up automation processes by loading SAGE node, agent, and behavior configurations to quickly restore previously saved network states. + + .. container:: two-caption + + .. figure:: _images/features_5.png + + + +`"Robot Framework" `_ by Robot Framework Foundation is licensed under the `Apache License 2.0 `_ \ No newline at end of file diff --git a/docs/_build/html/_sources/help.rst.txt b/docs/_build/html/_sources/help.rst.txt new file mode 100644 index 0000000..c79e049 --- /dev/null +++ b/docs/_build/html/_sources/help.rst.txt @@ -0,0 +1,90 @@ +Help and FAQ +=============================== + +- `Do I need to install both the Server and the Node on every machine?`_ +- `How can I verify the server is running?`_ +- `Is there a default port number that is commonly used?`_ +- `When I deploy SAGE agents to other VMs, how can I verify that they are fully operational?`_ +- `Why am I getting a python27.dll is missing error when attempting to connect a SAGE Node?`_ +- `Why am I getting a jvm.dll is missing error when attempting to connect a SAGE Node?`_ +- `Why am I receiving a 'sageframework.SageLocalInterfaceWrapperPINVOKE' exception upon starting the SAGE App?`_ +- `How do I resolve "error while loading shared libraries: libjvm.so" when starting a Node on Linux?`_ +- `Why am I getting "ImportError: No module named robot"?`_ +- `Why do I receive "WARNING: An illegal reflective access operation has occurred" upon running a Robot file?`_ +- `Why does the SAGE App not open?`_ + + +.. _`Do I need to install both the Server and the Node on every machine?`: + +**Do I need to install both the Server and the Node on every machine?** + +No. Only one Server instance is required. All tests are to be launched from the machine that has the SAGE Server instance. The Server will distribute behavior files to the target Nodes via message. This gives SAGE users the ability to control complex test scenarios, involving multiple nodes and agents across various machines, from a single controller entity. + +.. _`How can I verify the server is running?`: + +**How can I verify the server is running?** + +To verify a running SAGE Server instance, check the prompt window and confirm that the following text is displayed, "SAGE server started listening on port: {portNumber}". This indicates that the SAGE Server is active and listening over the selected port. + +.. _`Is there a default port number that is commonly used?`: + +**Is there a default port number that is commonly used?** + +There is no default port number for SAGE. It is recommended to avoid using dedicated port numbers, such as 21 (FTP), 22 (SSH), and 80 (HTTP). For a list of unassigned port numbers visit `Internet Assigned Numbers Authority (IANA) `_. + + +.. _`When I deploy SAGE agents to other VMs, how can I verify that they are fully operational?`: + +**When I deploy SAGE agents to other VMs, how can I verify that they are fully operational?** + +It is important to not confuse the terms SAGE agents and SAGE nodes. SAGE agents are created on-the-fly using a SAGE controller interface (Robot Framework by default). Currently, there is only support for agent creation using Robot Keyword, ``Create Agent``. When you create an agent, it is deployed to a SAGE Node. SAGE nodes are containers that are deployed to a VM/machine. These containers store agents upon their creation. + +When you initialize a node, you will assign it a IP Address and a port number value. The IP Address value should be the IP Address of the server VM/machine. The port number must match that of the recipient server's port number. A matching port number and valid IP is essential for connecting a node to the intended SAGE Server. Once connected, check the prompt window for the following text, "Connected to SAGE runtime using ip address {server_IP_address} : {portNumber}", to verify the node is operational. It is recommended to download the example files to get a better understanding of the SAGE Node deployment and agent creation process. + + +.. _`Why am I getting a python27.dll is missing error when attempting to connect a SAGE Node?`: + +**Why am I getting a python27.dll is missing error when attempting to connect a SAGE Node?** + +This error either means there are multiple Python instances installed on your machine, a non-supported Python version installed on your machine, or your installed Python bit version differs from that of the installed SAGE. SAGE currently supports `Python 2.6 or 2.7 `_. Be sure you have one of the two installed. Next, be sure the bit version is consistent with the installed SAGE bit version. To check the Python bit version, start Python in the command prompt and it will display the bit number. Check your Python directory :mod:`e.g C:\\Python27` and verify that the python27.dll file is there. If not, it is recommended to uninstall the current Python instance and to do a fresh install. Be sure your :ref:`envvar-label` ``PYTHONHOME`` and ``PATH`` are set and updated, respectively. Visit `here `_ to learn how to add and edit environment variables. + + +.. _`Why am I getting a jvm.dll is missing error when attempting to connect a SAGE Node?`: + +**Why am I getting a jvm.dll is missing error when attempting to connect a SAGE Node?** + +This error either means there are multiple Java instances installed on your machine, a non-supported Java version installed on your machine, or your installed Java bit version differs from that of the installed SAGE. SAGE currently supports `Java 8 `_ . Be sure you have a supported version installed. Next, be sure the bit version is consistent with the installed SAGE bit version. To check the Java bit version, type :mod:`java -version` in the command prompt. Check your Java JDK server directory :mod:`e.g C:\\Program Files\\Java\\jdk1.8.0_91\\jre\\bin\\server` and verify that the jvm.dll file is there. If not, it is recommended to uninstall the current Java instance and to do a fresh install. Be sure your :ref:`envvar-label` ``JAVAHOME`` and ``PATH`` are set and updated, respectively. Visit `here `_ to learn how to add and edit environment variables. + + +.. _`Why am I receiving a 'sageframework.SageLocalInterfaceWrapperPINVOKE' exception upon starting the SAGE App?`: + +**Why am I receiving a 'sageframework.SageLocalInterfaceWrapperPINVOKE' exception upon starting the SAGE App?** + +The SAGE App goes through a behavior discovery process to locate local "Native", "Java", and "Python" behavior files. This exception is thrown if both Java and Python are not found on your machine. Be sure your :ref:`envvar-label` ``PYTHONHOME``, ``JAVAHOME``, and ``PATH``, are set and updated. Visit `here `_ to learn how to add and edit environment variables. + + +.. _`How do I resolve "error while loading shared libraries: libjvm.so" when starting a Node on Linux?`: + +**How do I resolve "error while loading shared libraries: libjvm.so" when starting a Node on Linux?** + +SAGE needs JVM dynamic library to be in the runtime library search path. This is accomplished by including the location in the :mod:`LD_LIBRARY_PATH` environmentvariable. This is typically done by including the definintion in .bashrc file or .profile file. It can also be temporarily set using the same command, typically: :mod:`export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:{JRE_HOME}/lib/amd64/server` + +.. _`Why am I getting "ImportError: No module named robot"?`: + +**Why am I getting "ImportError: No module named robot"?** + +This error is returned when the robot framework module cannot be found. By default, robot-framework is distributed with SAGE and appended to the :ref:`envvar-label` ``SAGE_CLASSPATH`` system Environment variable upon install. Be sure to verify that the robotframework-2.9.2.jar is located in the *"C:\\Program Files\\NRL\\SageServer"* directory. In addition, check the :ref:`envvar-label` ``SAGE_CLASSPATH`` environment variable to ensure the absolute path to the jar *"C:\\Program Files\\NRL +\\SageServer\\robotframework-2.9.2.jar"* has been added and appears as the first item in the list. + + +.. _`Why do I receive "WARNING: An illegal reflective access operation has occurred" upon running a Robot file?`: + +**Why do I receive "WARNING: An illegal reflective access operation has occurred" upon running a Robot file?** + +This warning is a known issue in the current Robot Framework build and is caused by Java 9+ reflection and package access changes. You can continue with testing until Robot Framework pushes a new update to address the changes. + +.. _`Why does the SAGE App not open?`: + +**Why does the SAGE App not open?** + +If you said yes to Python, make sure you have ``PYTHONHOME`` set correctly and that it is in your ``PATH``. \ No newline at end of file diff --git a/docs/_build/html/_sources/how_it_works.rst.txt b/docs/_build/html/_sources/how_it_works.rst.txt new file mode 100644 index 0000000..6695200 --- /dev/null +++ b/docs/_build/html/_sources/how_it_works.rst.txt @@ -0,0 +1,110 @@ +How It Works +========================== + +SAGE execution is summarized in these following steps: + +1. `Starting a SAGE Server instance.`_ +2. `Connecting SAGE Node instance to SAGE Server.`_ +3. `Building an agent network.`_ +4. `Distributing Behaviors to target Nodes.`_ +5. `Activating agents.`_ +6. `Creating a test case that runs a behavior.`_ +7. `Logging the events, collecting the results.`_ + + +.. figure:: _images/sage_architecture.png + :align: center + + + +An instance of a SAGE runtime consists of: + + - *ONE* instance of a SAGE Server + - *ONE or MORE* SAGE Node instances running on either the Server computer or on remote computers with network connectivity to the Server Computer. + - In addition, a SAGE Node instance may have *MULTIPLE* SAGE Agents which may each have *MULTIPLE* Behaviors. + + +.. _`Starting a SAGE Server instance.`: + +**1. Starting a SAGE Server instance** + +To begin automating your environment, you must first stand-up a single SAGE Server instance. + +The SAGE Server is the central component for your automation. It serves as a single-point of access for managing your Agent network, by handling communication and code (Behavior) distribution. + + + +.. _`Connecting SAGE Node instance to SAGE Server.`: + +**2. Connecting SAGE Nodes** + +The next step would be to stand-up your Node instances on all computers that are expected to execute any automation. This includes any local and remote machines. + +Nodes act as a containers for your Agents. While your Agents execute your automation code, the Nodes can be viewed as conductors for Agents. This means that the Server has fewer components to communicate with as it bypasses the need to have to communicate with an Agent directly. + +This also means that as a user, you will not have to manually configure multiple Agents across multiple machines. Instead, you can stand up a single Node and later automate the creation and deletion of Agents tied to that Node. + +This architecture was designed with scalability in mind. + + + +.. _`Building an agent network.`: + +**3. Adding agent entities to Nodes** + +You can begin populating your Nodes with Agents as soon as your Nodes are initialized. This can be done via manual configuration or it can be automated by either coding it into Behaviors or through an external controller mechanism. + +This gives you the possibility of dynamically building an agent network. + + + +.. _`Distributing Behaviors to target Nodes.`: + +**4. Managing Behaviors** + +Behaviors are only sent to Agents on an as-needed basis. This minimizes overhead and gives Agents the flexibility of learning and unlearning skills on demand. + +All Behaviors are stored in a single repository on the Server machine. When requested, the Behavior module will be sent from the Server to a remote Node. From there, the selected Agent will be granted access to the file. + +This means that you will not have to worry about manually copying code across multiple machines during configuration. + + +.. _`Activating agents.`: + +**5. Activating agents** + +You are ready to activate your Agents once you have established connection between your Server and Nodes and have populated your Server with the necessary Behavior modules. + +Agents must first be activated in order to receive any updates from the network. Thus, an agent that is not activated will not receive incoming messages. + +Upon activation, your Agents may respond reactively or proactively depending on what Behaviors it contains and how those Behaviors are constructed. + +Reactive execution occurs when an Agent perfroms some action upon receiving any incoming message. + +Proactive execution can occur in multiple ways based on how an Agent's Behaviors are configured. + + + +.. _`Creating a test case that runs a behavior.`: + +**6. Running tests** + +You can build out a step-by-step test case using the Robot Frameworks integration into SAGE Framework as a controller mechanism. + +This integration allows you to send messages from the Controller. This message will propagate through the Server to the Node to instruct an Agent. + +Upon receiving messages, your Agents will begin executing their coded automation abilities. + + +.. _`Logging the events, collecting the results.`: + +**7. Capturing test results** + +During automation, any pertinent information can be captured by Behaviors and reported as an execution result. + +All information, including execution results as well as SAGE log events, are propagated back to the Server to be stored in a single location. This means you will not have to manually check multiple computers to verify your results. + +Instead, users only have to check the logs residing on the Server machine. + + + diff --git a/docs/_build/html/_sources/index.rst.txt b/docs/_build/html/_sources/index.rst.txt new file mode 100644 index 0000000..e24654c --- /dev/null +++ b/docs/_build/html/_sources/index.rst.txt @@ -0,0 +1,90 @@ +SAGE Framework’s Documentation +================================== + +.. toctree:: + :hidden: + :caption: Getting Started + + introduction + features + sage_server + sage_node + how_it_works + Download + installation + sage_app + +.. toctree:: + :hidden: + :caption: Building SAGE Network + + starting_a_server_instance + connecting_a_node_to_the_server + building_an_agent_network + +.. toctree:: + :hidden: + :caption: Creating Behaviors + + writing_a_sage_behavior + base_class_methods + retrieving_information_about_your_agent_network + sending_messages_between_agents + responding_to_a_message_sent_to_an_agent + +.. toctree:: + :hidden: + :caption: Managing Behaviors + + managing_behavior_files + adding_a_behavior_to_an_agent + using_supplemental_files_in_your_automation + +.. toctree:: + :hidden: + :caption: Starting Network + + activating_agents + +.. toctree:: + :hidden: + :caption: Running Tests + + robot_framework_background + creating_a_test_case_using_robot_framework + sage_robot_framework_keywords + running_your_automation_test + capturing_the_test_results + creating_your_own_controller_application + +.. toctree:: + :hidden: + :caption: Demonstration + + example + +.. toctree:: + :hidden: + :caption: About + + changelog + help + contact_us + +.. figure:: _images/sage_network.png + :align: center + +SAGE makes automating complex systems simple. +------------------------------------------------------------------------------------------------------------------------- + +Language Agnostic: + SAGE is designed so that behaviors can be written in a wide range of programming languages. SAGE currently supports behaviors written in C++, Java, and Python. + +Open Integration: + SAGE provides powerful software interfaces that facilitate tight integration between SAGE agents and external software systems. + +SAGE Clusters: + SAGE supports a fog computing model with dynamic discovery. SAGE servers can dynamically discover and connect to other server instances so that agents can communicate across cloud boundaries. + +Easy to use: + SAGE Server and Node are containerized so that they can be easily deployed where they are needed using any container management platform. diff --git a/docs/_build/html/_sources/installation.rst.txt b/docs/_build/html/_sources/installation.rst.txt new file mode 100644 index 0000000..64087bc --- /dev/null +++ b/docs/_build/html/_sources/installation.rst.txt @@ -0,0 +1,168 @@ +Installation +========================== + +.. _requirements-label: + +Requirements +--------------------------- + +Note that SAGE may be compatible with other versions of Windows and Linux distributions not listed below + + +- Windows 10, 11, Server 2016 +- Red Hat Enterprise Linux 8 +- Ubuntu 18 + + +Optional for development +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +- `Python `_ 3.10 +- `Java JDK `_ 11 and up. + + + +Windows +--------------------------- + +1. Start the SAGE Server or Node Installer executable +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +SAGE Server and Node softwares are packaged independently and include separate installers. + +After the SAGE distribution has finished downloading it should be available in your download directory. Start the SAGE Server or SAGE Node Installer executable. You may be asked to install Visuall C++ Runtime. If so, select ‘OK’ and proceeed. Select repair if needed. + +.. figure:: _images/sage_installer_imgs/visual_c_install.png + +Select the ‘Next’ button to continue with installing SAGE. + +.. figure:: _images/sage_installer_imgs/setup_begin.png + + +2. Review the SAGE license agreement +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Review the terms of agreement. To proceed, agree to the terms of the license agreement. + +Select the ‘Next’ button to continue. + +.. figure:: _images/sage_installer_imgs/setup_license.PNG + + +3. Select your installation folder +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Specify the folder where you want SAGE to be installed. The default folder will be in your Program Files directory. + +Select the ‘Next’ button to continue. + +.. figure:: _images/sage_installer_imgs/setup_filePath.png + + +4. Confirm SAGE installation ++++++++++++++++++++++++++++++++++++ + +Select the ‘Next’ button to begin the installation. You may get a security warning to run this file. Select ‘Yes’ to allow SAGE to proceed with installation. + +.. figure:: _images/sage_installer_imgs/setup_ready.png + + +5. Installation complete ++++++++++++++++++++++++++++ + +Once the installation is complete you can now launch SAGE. + +.. figure:: _images/sage_installer_imgs/setup_complete.png + + +.. _envvar-label: + +Environment variables +--------------------------- + +The following System variables will be automatically added: + +.. envvar:: SAGE_SERVER_HOME + + .. code-block:: bat + + C:\Program Files\NRL\SageServer + + +.. envvar:: SAGE_CLASSPATH + + .. code-block:: bat + + %SAGE_SERVER_HOME%;%SAGE_SERVER_HOME%\robotframework-2.9.2.jar;%SAGE_SERVER_HOME%\SageRemoteInterface.jar;%SAGE_SERVER_HOME%\SageJavaBehaviorInterface.jar + +.. envvar:: SAGE_NODE_HOME + + .. code-block:: bat + + C:\Program Files\NRL\SageNode + +**Update your PATH System variable** + +Java installation requires access to *jvm.dll* and *java.exe*. + +.. envvar:: PATH + + .. code-block:: bat + + For Java JDK users: "C:\Program Files\Java\jdk1.8.0_xx\bin;C:\Program Files\Java\jdk1.8.0_xx\jre\bin\server" + +Python requires access to *python.exe*. + + .. code-block:: bat + + For Python users: "C:\Python27" + + + +.. _linux-install: + +Installation on Linux +----------------------------- + +On a terminal enter the following command, assuming the current sage distribution rpms are in the local folder: + +.. code-block:: bat + + sudo rpm -Uvh nrl-sage-node-*.rpm + +Note that the SDK package is optional and needed only for C++ behavior development. Java and Python Behaviors can be developed without it. Note that the Linux Server is still considered to be an experimental version. To install the SDK and Server: + +.. code-block:: bat + + sudo rpm -Uvh nrl-sage-sdk-*.rpm + sudo rpm -Uvh nrl-sage-server-*.rpm + + +If you're on a Debian based Linux that does not have rpm, such as Ubuntu, you can install the alien package. Then the above rpm commands will work. + +.. code-block:: bat + + sudo apt-get install alien + +**Environment variables** + +SAGE Node needs the Java JVM dynamic library to be in the runtime library search path. This is accomplished by including its location in the ``LD_LIBRARY_PATH`` environment variable. This is typically done by including the definition in .bashrc file or .profile file. + +It can also be temporarily set using the same command, typically: + +.. envvar:: LD_LIBRARY_PATH + + .. code-block:: bat + + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:{JRE_HOME}/lib/amd64/server + +If you intend to use the Robot Framework on Linux with the SAGE Server you will need to define the ``SAGE_ROBOT_LIBRARY`` environment variable. + +.. envvar:: SAGE_ROBOT_LIBRARY + + .. code-block:: bat + + export SAGE_ROBOT_LIBRARY=SageRemoteInterface + + + diff --git a/docs/_build/html/_sources/introduction.rst.txt b/docs/_build/html/_sources/introduction.rst.txt new file mode 100644 index 0000000..733e061 --- /dev/null +++ b/docs/_build/html/_sources/introduction.rst.txt @@ -0,0 +1,27 @@ +Introduction +================================== + +Sentry AGEnts (SAGE) is a multi-agent software framework that provides a platform for exploring, developing, and deploying agent-based software systems. We designed SAGE as a foundational infrastructure that can be used to find novel ways to solve problems across a wide range of applications. For example, SAGE is being used to automate the test and validation of highly complex Service Oriented Architecture systems-of-systems, to explore autonomous control of swarms of unmanned systems that must operate in disconnected network environments, to monitor the performance of deployed machine learning (ML) systems to measure model drift, and to explore the use of emergent configurations (EC) of agents that make use of IoT systems to achieve a goal. +SAGE maintains a small footprint; it is implemented in C++ and uses an extremely efficient, and widely used interprocess communication capability, Remote Call Framework, for agent interaction, (See https://www.deltavsoft.com). + +The design of SAGE was influenced by `Herbert Simon's`_ ideas on the architecture of complexity. SAGE inherently supports the idea of emergent configurations through dynamical agent composition by other agents. The basic premise is to manage complexity through intelligent, agent driven task decomposition. An agent can reason about the components needed to perform a task. That agent composes new agents capable of performing each sub-task, and deployes them to do their work. Applying this approach recursively, a pyramidal structure of agents forms, where the leaf agents perform tasks and report results to their parent agent. Once the process completes, the agent at the apex of the pyramid receives the results of the task execution. + +.. _`Herbert Simon's`: https://en.wikipedia.org/wiki/Herbert_A._Simon + +While SAGE adheres to proper agent semantics, it was designed to be pragmatic so that it can easily integrate into new or existing software systems and infrastructure. SAGE provides interface libraries that allow external systems to build, control, and interact with SAGE agent networks. SAGE agents can also interact with their surrounding environment in a number of ways: they can make use of XaaS services to gather data or extend their capabilities, they can interact directly with other software systems via their interfaces, or they can interact with hardware systems through I/O ports or memory manipulation. + +SAGE is free software and has no dependencies that require paid licenses or impose restrictions on distribution. SAGE is an open, containerized system that can run on a wide range of platforms ranging from servers to IoT devices. To support experimentation, SAGE includes an interactive agent development environment called SAGE Server App where you can interactively build, experiment with, visualize, and store agent networks. + +.. figure:: _images/introduction_1.png + :width: 650 px + :align: center +| +SAGE is simple to use and consists of four parts: + + **SAGE Server** is a console appication available for both Windows and Linux. SAGE Server acts as the hub of a SAGE agent nework. It interacts with other SAGE components to provide them with services, manage communications, maintain system state, log system events, and provide introspection services. + + **SAGE Node** is also a console application available for both Windows and Linux. SAGE Node acts as a container for SAGE agents, managing their execution and maintining connectivity to the SAGE Server. SAGE Node is designed to be portable across a wide variety of system architectures. Multiple instances of SAGE Node can be distributed across a network of computing devices of various architectures. SAGE Framework manages the data translation between different architectures trasparently. + + **SAGE Agents** are automous agents consisting of a repitoir of Behaviors and a state. SAGE agents exist within a SAGE Node and can communicate with other agents using message passing. Agents can have any number of Behaviors each consisting of a mix of C++, Java, or Python modules. Behaviors are stored in a centeral repository on the SAGE Server and are sent to agents at runtime on demand. + + **SAGE Behaviors** are objects that are derived from base classes provided with the SAGE Framework. A SAGE behavior endows an Agent with the capability to act either proactivily or reactively. \ No newline at end of file diff --git a/docs/_build/html/_sources/managing_behavior_files.rst.txt b/docs/_build/html/_sources/managing_behavior_files.rst.txt new file mode 100644 index 0000000..3e60d15 --- /dev/null +++ b/docs/_build/html/_sources/managing_behavior_files.rst.txt @@ -0,0 +1,37 @@ +Managing Behavior Files +=============================== + +The Server hosts and manages a Behavior repository located in the following directory: + ++-------------+----------------------------------+ +| | Behavior Path | ++=============+==================================+ +| **Windows** | C:\\ProgramData\\Sage\\behaviors | ++-------------+----------------------------------+ +| **Linux** | /etc/Sage/behaviors | ++-------------+----------------------------------+ + +Behavior files must be placed on the Server machine in order for the Server to distribute them across the network. This is because the SAGE runtime looks inside these directory paths before deploying an executable module to a target Node. + +**Updating files using SAGE App** + +It is recommended to use the :mod:`Behavior Manager` found within the SAGE App to manage your Behaviors. +It provides a syntax check to ensure that the file you are attempting to upload is a properly written and supported SAGE Behavior. + + 1) In the SAGE App, click the :mod:`Behavior Manager` button. + 2) Select the :mod:`Manage` drop-down menu and click :mod:`Add Modules`. + 3) Select the targeted file and click :mod:`Ok`. + + Upon successful upload, your file will be copied to the proper sub-directory. + +**Manually updating files** + +The behaviors directory contains sub-directories for SAGE supported languages :mod:`C++`, :mod:`Java`, and :mod:`Python`. + +| :mod:`Windows64`, :mod:`Windows32`, :mod:`Linux64`, :mod:`Linux32` C++ behavior files directory - Behavior.cpp +| :mod:`Python` Python behavior files directory - Behavior.egg +| :mod:`Java` Java behavior files directory - Behavior.jar + +You can manually move your Behaviors to their corresponding sub-directory. + +Only SAGE Behaviors should reside in the Behavior directory. Supplemental libraries or files should not be stored within the Behavior repository. \ No newline at end of file diff --git a/docs/_build/html/_sources/responding_to_a_message_sent_to_an_agent.rst.txt b/docs/_build/html/_sources/responding_to_a_message_sent_to_an_agent.rst.txt new file mode 100644 index 0000000..c5ea939 --- /dev/null +++ b/docs/_build/html/_sources/responding_to_a_message_sent_to_an_agent.rst.txt @@ -0,0 +1,227 @@ +Responding to a Message Sent to an Agent +======================================================================= + +Depending on the Behavior construction, an agent will perform either **reactively** in response to an incoming message or **proactively** upon the receipt of a specific trigger message (m_triggerMessage) or at activation. Your can support both types of execution within a single Behavior file. + +**Reactive Response** + +Reactive responses are handled within your Behavior :mod:`message` method. Any code found within the :mod:`message` method will be called once your targeted Agent receives any message. + +To avoid invoking the wrong Behavior file, you can specify a specific topic (m_topic) within the senders Message object which matches the list of topics that the Behavior is interested in. Topics are associated with Behaviors when you add them to an agent. + + +Here's an example of a Message being sent by senderAgent: + +.. code-block:: java + + Message myMessage = new Message(); + + myMessage.m_message = "Hello"; + myMessage.m_targetNodeName = "recipientNode"; + myMessage.m_targetAgentName = "recipientAgent"; + myMessage.m_topic = "Topic1"; + sendMessage(myMessage); + +Assuming recipientAgent has a Behavior that is associated with the topic "Topic1": + +.. code-block:: java + + addBehavior("recipientNode", "recipientAgent", "ExampleBehavior", "ExampleBheavior.jar", "Topic1"); + + +And by setting my execution type (m_executionType) to :mod:`NoExecution` within my Behavior's constructor, I ensure the action() method won't be called: + +.. code-block:: java + + public ExampleBehavior() + { + m_executionType = ExecutionType.NoExecution; + m_description = "Example Behavior"; + m_name = "ExampleBehavior"; + } + + public boolean setUp(Result result) + { + System.out.println("begin"); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + public boolean action(Result result) + { + System.out.println("Hello World from Action"); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + public boolean message(Message message, Result result) + { + System.out.println("Got message "+ message.m_message + " on topic " + message.m_topic); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + public boolean tearDown(Result result) + { + System.out.println("end"); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + +If all goes well, you should see the following response from the recipient (recipientAgent). + +.. code-block:: bat + + begin + Got message Hello on topic Topic1 + + +Here's the same example of a Message being sent by the Server instead: + + 1) In the SAGE App select :mod:`Send Message` to recipientAgent on recipientNode. + 2) Type message "Hello". + 3) Type topic "Topic1". + 4) Click the :mod:`Ok` button. + + +If all goes well, you should see the same response as above from the recipient (recipientAgent). + +.. code-block:: bat + + begin + Got message Hello on topic Topic1 + +**Proactive Response** + +Proactive responses are handled within your Behavior :mod:`action` method. Any code found within the :mod:`action` method will be called once your targeted Agent receives the trigger message. + + +Here's an example of a Message being sent by senderAgent: + +.. code-block:: java + + Message myMessage = new Message(); + + myMessage.m_message = "Bye"; + myMessage.m_targetNodeName = "recipientNode"; + myMessage.m_targetAgentName = "recipientAgent"; + sendMessage(myMessage); + + +By setting my execution type (m_executionType) to :mod:`OnMessage` and specifying a trigger message within my Behavior's constructor, I can invoke the action() method: + +.. code-block:: bat + + public ExampleBehavior() + { + m_executionType = ExecutionType.OnMessage; + m_description = "Example Behavior"; + m_name = "ExampleBehavior"; + m_triggerMessage = "Bye"; + + } + + public boolean setUp(Result result) + { + System.out.println("begin"); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + public boolean action(Result result) + { + System.out.println("Hello World from Action"); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + public boolean message(Message message, Result result) + { + System.out.println("Got message "+ message.m_message + " on topic " + message.m_topic); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + public boolean tearDown(Result result) + { + System.out.println("end"); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + +If all goes well, you should see the following response from the recipient (recipientAgent). + +.. code-block:: bat + + begin + Hello World from Action + +Here's the same example of a Message being sent by the Server instead: + + 1) In the SAGE App select :mod:`Send Message` to recipientAgent on recipientNode. + 2) Type message "Bye". + 3) Click the :mod:`Ok` button. + + +If all goes well, you should see the same response as above from the recipient (recipientAgent). + +.. code-block:: bat + + begin + Hello World from Action + +You can also make use of :mod:`OneShot, Cyclical, or TimedCyclical` proactive execution types (m_executionType), which respond as soon as the Agent has been activated, to get the best of both worlds: + + +.. code-block:: bat + + public ExampleBehavior() + { + m_executionType = ExecutionType.OneShot; + m_description = "Example Behavior"; + m_name = "ExampleBehavior"; + + } + + public boolean setUp(Result result) + { + System.out.println("begin"); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + public boolean action(Result result) + { + System.out.println("Hello World from Action"); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + public boolean message(Message message, Result result) + { + System.out.println("Got message "+ message.m_message); + setAgentActive("recipientNode","recipientAgent", false); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + public boolean tearDown(Result result) + { + System.out.println("end"); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + + +Assuming the recipientAgent got a message AFTER the agent was activated, you should see the following response from the recipient (recipientAgent). + +.. code-block:: bat + + begin + Hello World from Action + Got message Bye + end + +In this example, teardown() method was invoked last as the agent was deactivated using the setAgentActive(false) method. \ No newline at end of file diff --git a/docs/_build/html/_sources/retrieving_information_about_your_agent_network.rst.txt b/docs/_build/html/_sources/retrieving_information_about_your_agent_network.rst.txt new file mode 100644 index 0000000..b5b8bd7 --- /dev/null +++ b/docs/_build/html/_sources/retrieving_information_about_your_agent_network.rst.txt @@ -0,0 +1,287 @@ +Retrieving Information About Your Agent Network +================================================================================ + +SAGE Agents will often need to find the names of SAGE Nodes that are part of the network as well as the names of SAGE Agents residing at a specific node. SAGE uses a query message send and reply protocol to provide this introspection capability. + +SAGE Agents can send query messages to the SAGE Server by specifying :mod:`sage` as the target Node in the Message object (m_targetNodeName). The type of query requested is specified in the message itself (m_message). + +Replies are sent by the SAGE Server to the originating SAGE Agent and contain the original query in the m_message, while the results of the query are returned data element, m_data, of the Message object. Simple queries that request an enumeration of Node and Agent names receive a reply with the Node or Agent names as a string vector in m_data. Deeper queries that request all the relevant information about Nodes or Agents recieve a reply with a JSON object in the first element of the m_data vector (m_data[0]). + +The following introspection queries are supported by SAGE: + +**Querying the names of all the SAGE Nodes in the network** + +To get the names of all the SAGE Nodes in the network, the message (m_message) should equal ``getNodeNames``. + +Here's an example of a ``getNodeNames`` query generated in a Java behavior: + +.. code-block:: Java + + Message myMessage = new Message(); + + myMessage.m_message = "getNodeNames"; + myMessage.m_targetNodeName = "sage"; + sendMessage(myMessage); + +In response to this query, the SAGE Server would reply to the sender with a Message containing the following: + +.. code-block:: bat + + m_message = "getNodeNames" + m_topic = "sage" + m_data[0] = "nodeName1" + . + . + m_data[n - 1] = "nodeNameN" + +**Querying the names of all the SAGE Agents in the network** + +To get the names of SAGE Agents at a specific SAGE Node, message (m_message) should equal ``getAgentNames`` with the name of the SAGE Node included as the first string data element in the Message object (m_data[0]). + + +Here's an example of a ``getAgentNames`` query generated in a Java behavior: + +.. code-block:: Java + + Message myMessage = new Message(); + + myMessage.m_message = "getAgentNames"; + myMessage.m_targetNodeName = "sage"; + myMessage.m_data.add("nodeName1"); + sendMessage(myMessage); + +In response to this query, the SAGE Server would reply to the sender with a ``Message`` containing the following: + +.. code-block:: bat + + m_message = "getAgentNames" + m_topic = "sage" + m_data[0] = "newAgentName1" + . + . + m_data[n - 1] = "newAgentNameN" + +**Querying all of the SAGE Nodes in the network** + +To get detailed information on all of the SAGE Nodes in a nework, message (m_message) should equal ``getNodes``. + +Here's an example of a ``getNodes`` query generated in a Java behavior: + +.. code-block:: Java + + Message myMessage = new Message(); + + myMessage.m_message = "getNodes"; + myMessage.m_targetNodeName = "sage"; + sendMessage(myMessage); + +In response to this query, the SAGE Server would reply to the sender with a ``Message`` containing the following: + +.. code-block:: bat + + m_message = "getNodes" + m_topic = "sage" + m_data[0]= + { + "nodes": { + "Node1": { + "agents": { + "Agent1": { + "behaviors": { + "ExampleJavaBehavior": { + "module": "ExampleJavaBehavior.jar", + "targetEnvironment": "Any" + } + } + }, + "Agent2": { + "behaviors": { + "Hello": { + "module": "hello.jar", + "targetEnvironment": "Any" + } + } + } + }, + "runtimeEnvironment": "Windows64", + "ipAddress": "127.0.0.1" + }, + "Node2": { + "agents": { + "Agent3": { + "behaviors": { + "TestGetNode": { + "module": "TestGetNode.jar", + "targetEnvironment": "Any" + } + } + }, + "Agent4": { + "behaviors": { + "ExampleJavaBehavior": { + "module": "ExampleJavaBehavior.jar", + "targetEnvironment": "Any" + } + } + } + }, + "runtimeEnvironment": "Windows64", + "ipAddress": "127.0.0.1" + } + } + } + +**Querying a specific SAGE Node in the network** + +To get detailed information of a single SAGE Node, message (m_message) should equal ``getNode`` and the first element of m_data (m_data[0]) should contain the target Node's name. + +Here's an example of a ``getNode`` query generated in a Java behavior: + +.. code-block:: Java + + Message myMessage = new Message(); + + myMessage.m_message = "getNode"; + myMessage.m_targetNodeName = "sage"; + message.m_data.add("Node1"); + sendMessage(myMessage); + +In response to this query, the SAGE Server would reply to the sender with a ``Message`` containing the following: + +.. code-block:: bat + + m_message = "getNode" + m_topic = "sage" + m_data[0] = + { + "Node1": { + "agents": { + "Agent1": { + "behaviors": { + "ExampleJavaBehavior": { + "module": "ExampleJavaBehavior.jar", + "targetEnvironment": "Any" + } + } + }, + "Agent2": { + "behaviors": { + "Hello": { + "module": "hello.jar", + "targetEnvironment": "Any" + } + } + } + }, + "runtimeEnvironment": "Windows64", + "ipAddress": "127.0.0.1" + } + } + +**Querying all of the SAGE Agents in the network** + +To get detailed information on all of the SAGE Agents in a network, message (m_message) should equal ``getAgents`` and the first element of m_data (m_data[0]) should contain the target Node's name. + +Here's an example of a ``getAgents`` query generated in a Java behavior: + +.. code-block:: Java + + Message myMessage = new Message(); + + myMessage.m_message = "getAgents"; + myMessage.m_targetNodeName = "sage"; + message.m_data.add("Node1"); + sendMessage(myMessage); + +In response to this query, the SAGE Server would reply to the sender with a ``Message`` containing the following: + +.. code-block:: bat + + m_message = "getAgents" + m_topic = "sage" + data[0] = + { + "agents": { + "Agent1": { + "behaviors": { + "ExampleJavaBehavior": { + "module": "ExampleJavaBehavior.jar", + "targetEnvironment": "Any" + } + } + }, + "Agent2": { + "behaviors": { + "Hello": { + "module": "hello.jar", + "targetEnvironment": "Any" + } + } + } + } + } + +**Querying a specific SAGE Agent in the network** + +To get detailed information on a specific SAGE Agent in a network, message (m_message) should equal ``getAgent`` and the first element of m_data (m_data[0]) should contain the target Node's name. The second element of m_data (m_data[1]) should contain the Agent's name. + +Here's an example of a ``getAgent`` query generated in a Java behavior: + +.. code-block:: Java + + Message myMessage = new Message(); + + myMessage.m_message = "getAgent"; + myMessage.m_targetNodeName = "sage"; + message.m_data.add("Node1"); + message.m_data.add("Agent1"); + sendMessage(myMessage); + +In response to this query, the SAGE Server would reply to the sender with a ``Message`` containing the following: + +.. code-block:: bat + + m_message = "getAgent" + m_topic = "sage" + data[0] = + { + "Agent1": { + "behaviors": { + "ExampleJavaBehavior": { + "module": "ExampleJavaBehavior.jar", + "targetEnvironment": "Any" + } + } + } + } + +**Getting the name of the originating Agent and its Node** + +There may be instances where you need to know information about the Agent who is currently using your Behavior, such as what Node it resides on. For instance, you may want to ensure that you create a new agent on the same node as the originating Agent. + +To achieve this, agents contain a state space that is shared by all the agents' behaviors. State space consists of name-value pairs where name is a unique string identifying a state variable and value is one of the following value types: double-precision floating-point number, a long integer, or a string. + +Behaviors can create, remove, or modify the value of state variables. SAGE guarantees that state space is always synchronized across behavior executions. + +SAGE provides two standard state values of type string that are available to behaviors: + +- :mod:`node` is the name of the SAGE Node where the behavior's agent resides +- :mod:`agent` is the name of that agent. + + +Use either the :mod:`getState` or :mod:`getStateNames` methods to return the Agent's state space information + +.. code-block:: Java + + System.out.println(getState("node")); + System.out.println(getState("agent")); + System.out.println(getStateNames()); + +If all goes well, you should see the following response + +.. code-block:: Java + + nodeName1 + newAgentName1 + [nodeName1, newAgentName1] + diff --git a/docs/_build/html/_sources/robot_framework_background.rst.txt b/docs/_build/html/_sources/robot_framework_background.rst.txt new file mode 100644 index 0000000..fd074a0 --- /dev/null +++ b/docs/_build/html/_sources/robot_framework_background.rst.txt @@ -0,0 +1,166 @@ +Robot Framework Background +=============================== + +| `"Robot Framework" `_ by Robot Framework Foundation is licensed under the `Apache License 2.0. `_ +| All information presented is derived from `Robot Framework User Guide `_ . +| +| + +Robot Framework is a generic test automation framework that uses the keyword-driven testing approach. + +Keyword-driven testing uses keywords (or action words) to perform a specific task. + +- Facilitates simple to use tabular syntax to create test cases. +- Generates easy to read result reports as well as logs in HTML format. +- Independent of application and platform. +- Supports creation of data driven test cases. +- Provides tagging for categorizing and selecting test cases that are to be executed. +- Has built in support for variables to enable testing in different environments. + +**File extension** + +Starting from Robot Framework 2.7.6, every robot framework file is saved as a .ROBOT file extension type. + + | e.g., *sageTest.robot* + +**Settings** + +Robot Framework test data is defined in tabular format, thus all content outside of the recognized table types is ignored. + +The asterisk (*) symbol is used to distinguish each table. When creating each table you can input "*", "**", or "*******" before you add the name of the +table. For consistency purposes it is common to use "*******" before you add the table name. Be sure that the table name is spaced between the +asterisks. + +.. code-block:: bat + + *** Settings *** + +Four common settings are *[Documentation]*, *[Library]*, *[Test Setup]*, and *[Test Teardown]*. + + +**Documentation** + +The *[Documentation]* setting allows you specify documentation of a test case. The supporting text is shown in both the command line output, as well as the test logs and reports. + +.. code-block:: bat + + *** Settings *** + Documentation Written explanation of test case to be documented + + +**Library** + +Importing supporting Robot Framework libraries is essential to make use of its keywords and their functionality. Test libraries may be imported using the *[Library]* setting. + +The library name is both case- and space-sensitive. If a library is in a package, the full name including the package name must be used. + +.. code-block:: bat + + *** Settings *** + Documentation Written explanation of test case to be documented + + Library SageRobotKeywords + + +The Library setting is Robot Framework’s equivalent of Java’s and Python’s respective import statement. Import SageRobotKeywords to use SAGE Framework specific keywords. + + +**Test Setup** + +The *[Test Setup]* setting allows you to run a Keyword before running your test case. This is useful for setting up your environment prior to conducting your test, such as configuring your network or having the proper windows open. + +.. code-block:: bat + + *** Settings *** + Documentation Written explanation of test case to be documented + + Library SageRobotKeywords + Test Setup Start SAGE + +**Test Teardown** + +The *[Test Teardown]* setting allows you to run a Keyword after your test case either completes or fails. This is useful for performing any clean-up and shutdown activities, such as deactivating your agents or closing any active windows. + +.. code-block:: bat + + *** Settings *** + Documentation Written explanation of test case to be documented + + Library SageRobotKeywords + Test Setup Start SAGE + Test Teardown Deactivate Agent MyNode MyAgent + + +**Test case** + + +The first column in the **Test Cases** table contains the test case name + +.. code-block:: bat + + *** Test Cases *** + TestName + +*"TestName"* is the name of the test case, while **"Test Cases"** is the table name. + +A test case concludes once a new test case or table is declared or if the current test reaches its final keyword. + + +**Keywords** + + +Keywords are considered as functions or methods that can be used for testing. Each keyword correspond to a set of actions. + +Keywords are specified in the second column. Keywords are ``Start SAGE`` and ``Connect to SAGE Runtime``. Columns after the keyword name contain possible arguments to the specified keyword. Arguments are **server_IP_address** and **port_number**. + +Robot Framework recommends using *four spaces between columns*. + +.. code-block:: bat + + *** Test Cases *** + TestName + Start SAGE + Connect to SAGE Runtime {server_IP_address} {port_number} + + +**Comments** + +In order to comment out a line include the pound (#) symbol. + +.. code-block:: bat + + *** Test Cases *** + TestName + Start SAGE + Connect to SAGE Runtime {server_IP_address} {port_number} + # This keyword is commented out + + + +**Arguments** + +Keywords may accept zero or more arguments. The number of arguments a keyword accepts depends on its implementation, and typically the best place to search for this information is located in a keyword's documentation (if supplied by the developer). + +If an argument has a default value you may specify that value by separating the argument name and its value with an equal sign. + +.. code-block:: bat + + *** Test Cases *** + TestName + Start SAGE + Connect to SAGE Runtime {server_IP_address} {port_number} + # This keyword is commented out + Create Agent nodeName=MyNode agentName=MyAgent + +**Robot file runtime** + +Robot Framework is executed in these following steps: + +1. Collecting test cases, reading and setting variables +2. Running all the steps in every test case +3. Providing the execution statistics (which test cases have passed/failed) +4. Writing the detailed log in xml format +5. Generating the report and log in html format. + +All executed test suites and test cases, as well as their statuses, are shown in real time. + diff --git a/docs/_build/html/_sources/running_your_automation_test.rst.txt b/docs/_build/html/_sources/running_your_automation_test.rst.txt new file mode 100644 index 0000000..1c225da --- /dev/null +++ b/docs/_build/html/_sources/running_your_automation_test.rst.txt @@ -0,0 +1,24 @@ +Running Your Automation Test +=============================== + +You are ready to execute your test once you have constructed your Robot file with the proper SAGE Keywords. + +All test cases are ran at the **Server level**. + +The Server will communicate with each connected Node, whether local or remote. This allows you to store all your test cases in a single location while testing across multiple network connected machines. + + +**Execute a robot file using the command-line** + + .. code-block:: bat + + java -cp "%SAGE_CLASSPATH%" org.robotframework.RobotFramework path/to/my_tests/Hello.robot + + +**Execute a robot file using the SAGE App** + + 1) In the SAGE App click the :mod:`Robot Interface` button. + 2) Click the :mod:`Add` button. + 3) Using the finder, select your Robot file. + 4) Once your Robot file has been added to the list, click the :mod:`Start` button. + \ No newline at end of file diff --git a/docs/_build/html/_sources/sage3_app.rst.txt b/docs/_build/html/_sources/sage3_app.rst.txt new file mode 100644 index 0000000..19226e1 --- /dev/null +++ b/docs/_build/html/_sources/sage3_app.rst.txt @@ -0,0 +1,1241 @@ +**SAGE Server Application** +=========================== + +The SAGE Server App provides a graphical user interface for viewing and +controlling the SAGE runtime environment. SAGE Server App supports the +following functions: + +- Manage behavior modules + +- Start and stop the SAGE server + +- View connected nodes + +- Manage nodes on the local server machine and networked remote + machines + +- Control node access to the server machine + +- Send files and messages to nodes + +- Create, activate, deactivate and remove agents + +- Send messages to agents + +- Add and remove agent behaviors + +- Select, sequence and run SAGE Robot files + +- View generated Robot reports + +- View SAGE server log output, including behavior execution results + +- Load and Save SAGE networks + +SAGE Server App is Windows compatible and distributed with the Windows +x64 - Server installer. + +To run SAGE Server App, double-click on the shortcut icon, or +right-click on the icon and select “Open” from the context menu. + +**Main Window** +=============== + +Following is an annotated view of the SAGE Server App window when the +application opens. + +.. image:: _images/serverapp3/image1.png + :width: 6.5in + :height: 6.5375in + +Control Toolstrip + +Provides buttons for: + +- Starting and stopping the SAGE Server. + +- Loading and Saving a SAGE network. + +- Configuring Server settings. + +- Displaying information about the SAGE Server and App. + +Server Toolstrip + +Provides buttons for viewing and controlling the SAGE network: + +- Manage SAGE Nodes on the local Server machine and networked remote + machines. + +- Manage SAGE Behaviors + +- Launch the SAGE Robot Interface + +- Create and remove Agents + +- Activate and deactivate Agents. + +- Add and remove Behaviors + +- View Behavior properties. + +- Send files to Nodes. + +- Send messages to Nodes and Agents. + +- View Agent State Space + +Network View Pane + +Allows you to view and control the SAGE network using the following +views: + +- Network Tree View + +- Network Graph View + +Views can be toggled by clicking on the respective tab. + +Logger Toolstrip + +Allows you to interact with server-generated log events. + +Provides buttons for: + +- Copying event logs to the Windows clipboard. + +- Clearing logs displayed in the Logger View Pane. + +- Controlling the scrolling of log events when the server is active. + +Logger View Pane + +Allows you to view server-generated log events, including behavior +execution results as they occur in real-time. + +**Server Settings** +=================== + +Clicking on the Settings button in the Control Toolstrip brings up the +Server Settings popup dialog. + +.. image:: _images/serverapp3/image2.png + :width: 6.5in + :height: 4.725in + +SAGE Server settings include the following: + +- Control Node access to the server machine. + +- Set Server IP port number + +- Set the maximum capacity of the SAGE event logger. + +- Adjusting window overlays. + +- Changing color theme of application. + +Node access control is enforced when Enable Node Access Control is +checked. This allows you to whitelist IP addresses in dot-decimal +notation. An asterisk may be used as a wildcard character for any of the +octet-grouped decimal numbers. Only IP addresses listed are allowed to +connect to the server. + +Setting the maximum capacity of the event logger prevents +Server-generated log events from overrunning memory when the Server runs +for very long periods of time (day or even weeks). When the maximum +capacity is reached, older events are removed to make room for new +events. + +Settings are automatically saved when the application terminates. + +**Network Tree View** +===================== + +The Network Tree View provides a tree view of the SAGE network when the +Server is active. + +- The root of the network tree is the NodeRoot tree-node representing + the set of all connected SAGE Nodes. + +- SAGE Nodes are shown as branches under the NodeRoot tree-node. Each + Node has an Agents tree-node representing the set of all Agents + belonging to the Node. + +- A Node’s Agents are shown as branches under the Agents tree-node. + Each Agent has a Behaviors tree-node representing the set of all + Behaviors belonging to the Agent. + +- An Agent’s Behaviors are shown as leaf tree-nodes under the Behaviors + tree-node. + +Clicking on any tree-node selects and highlights it. Tree-nodes +representing ancestor network entities are also selected. + +Right-clicking on a tree-node displays a set of cascading context menus +with a set of commands relevant to the current selection. + +You can expand and collapse tree-nodes by clicking on the plus or minus +sign next to a tree-node branch. + +Double-clicking on a tree-node fully expands a branch if it is +collapsed, and fully collapses a branch if it is expanded. + +.. image:: _images/serverapp3/image3.png + :width: 6.5in + :height: 5.92569in + +**Network Graph View** +====================== + +The Network Graph View provides a dynamic graph display of the SAGE +network when the Server is active. + +- The Server graph-node represents the SAGE Server and is always + visible when the Server is active. + +- SAGE Nodes are shown as root graph-nodes of their own sub-graphs. + +- Graph-nodes representing Agents are connected to their Node + graph-node, and graph-nodes representing Behaviors are connected to + their Agent graph-node. + +Clicking on any graph-node selects and highlights it. Graph-nodes +representing ancestor network entities are also selected. + +Right-clicking on a graph-node displays a set of cascading context menus +with a set of commands relevant to the selected object. + +Clicking on the Server graph-node or on the view background displays a +context menu relevant to the entire network. + +You can reposition entities within the graph region by dragging with the +left mouse button. + +Double-clicking on a graph-node centers the entity within the view pane. + +Double-clicking on the view background centers the graph region about +that position in the view pane. + +The graph view can be panned by clicking down anywhere in the view pane +that is not on a graph-node and dragging. + +.. image:: _images/serverapp3/image4.png + :width: 6.5in + :height: 5.92569in + +The graph view can be zoomed out and back in using the mouse wheel. When +zooming, the scaling is applied about the mouse cursor position. + +.. image:: _images/serverapp3/image5.png + :width: 6.5in + :height: 5.92569in + +**Starting the Server** +======================= + +Click the Start button or the Load Network button in the Control +Toolstrip to start the Server instance. After the Server has started, +any previously created Nodes will be connected and displayed in the +Network View Pane. + +If the Server is started using the Load Network button, a previously +saved Agent network is loaded. Nodes specified in the Agent network +which are not already running will be started. + +Once the Server becomes active, the Start button changes to a Stop +button and the Load Network button changes to a Save Network button. The +Server can be stopped at any time by clicking the Stop button. + +**Active Server** +================= + +When the Server is active, the current state of the network is reflected +in the Server Toolstrip and the Network View Pane. + +The following screenshot shows an active Server network, with the +Network Tree View displayed in the view pane. |image1| + +Clicking on the Network Graph View tab displays a graph-based view of +the network. + +.. image:: _images/serverapp3/image7.png + :width: 6.5in + :height: 5.92569in + +Nodes, their Agents and agent Behaviors are selected using either the +ServerToolstrip or Network View Pane. + +Commands operate on the current selection and are accessible from either +the Server Toolstrip or Network View Pane context menus. + +On the Server Toolstrip, node-related commands are under the Node +dropdown button, agent-related commands are under the Agent dropdown +button, and behavior-related commands are under the Behavior dropdown +button. + +.. image:: _images/serverapp3/image8.png + :width: 5.4253in + :height: 6.71875in + +When an individual Node, Agent or Behavior is not selected, the +corresponding dropdown button will display “(All Nodes)”, “(All +Agents)”, or “(All Behaviors)”, and the commands will apply to all +objects of that type. + +In the image above, clicking the agent Activate button on the Server +Toolstrip activates all inactive agents on all nodes in the network. + +The image below shows how to perform the same operation using the +Network View Pane: + +1. Right-click on one of the following to display the Network View Pane + context menu: + +- NodeRoot in the Network Tree View. + +- The Server graph-node in the Network Graph View. + +- The panel background in the Network Graph View. + +2. Move the mouse over (All Nodes) to display the cascading node context + menu. + +3. Move the mouse over (All Agents) to display the cascading agent + context menu. + +4. Click the Activate button on the agent context menu. + +|image2|\ |image3| + +Notice that commands in the cascading context menus match the commands +in the Server Toolstrip. + +In the Network Graph View, icons representing the newly activated Agents +change color from red (inactive) to green (active), and dynamic +messaging lines show the flow of messages sent between Agents. + +.. image:: _images/serverapp3/image11.png + :width: 6.5in + :height: 5.875in + +Click on the agent Deactivate button to deactivate all the Agents. + +**Selecting a SAGE Node, Agent or Behavior** + +A SAGE object (Node, Agent or Behavior) can be selected from the Server +Toolstrip or the Network View Pane. + +To select a Node, Agent or Behavior from the Network View Pane, click on +the corresponding tree-node or graph-node. + +To select a Node, Agent or Behavior from the Server Toolstrip, click on +the corresponding dropdown button and select the object’s name from the +popup combo box, as shown below. + +.. image:: _images/serverapp3/image12.png + :width: 3.89638in + :height: 4.7715in + +The current selection is reflected in both the Server Toolstrip and +Network View Pane (Tree View or Graph View). + +The mechanism for selecting SAGE objects and applying commands is +enforced by the topology of the Network Tree View and Graph View and by +the Server Toolstrip menu items. + +In the screen shot below, NodeFive is selected, but no Agent or Behavior +has been selected. + +- The node-related commands apply to NodeFive. + +- The agent-related commands apply to all the NodeFive Agents. + +- The behavior-related commands apply to all the Behaviors on all the + NodeFive Agents. + +|image4|\ |image5| + +The Server Toolstrip can be very useful when managing networks with a +large number of Nodes or Agents. + +In the following screenshot, the network has a single Node with 50 +Agents. Selecting an Agent using the Server Toolstrip is much easier +than trying to locate and select the Agent using either of the Network +Views. + +.. image:: _images/serverapp3/image15.png + :width: 6.5in + :height: 4.10208in + +The number of Agent names to scroll through in the toolstrip combo box +can be reduced by entering the first few letters of the name (e.g. “A2”) +in the combo box edit control. + +**The Node Manager** +==================== + +Use the SAGE Node Manager to start and stop Containerized and +NonContainerized Nodes on the Local Host computer, and containerized +nodes on networked Remote Host computers. SAGE Nodes can be started and +stopped at any time, even when the Server is inactive. + +The Node Manager is opened by clicking on the Node Manager button on the +Server Toolstrip or the Network View Pane context menu (when selecting +the NodeRoot in the Tree View or the Server graph-node or panel +background in the Graph View) . + +.. image:: _images/serverapp3/image16.png + :width: 6.5in + :height: 4.34236in + +The Network Tree at the left displays the current host network (the +Local Host and any managed Remote Hosts) and the SAGE nodes running on +each Host. The Information Pane at the right displays information about +the selected Node or Host tree-node. + +A Host is in the connected state if its icon is blue; a gray icon +indicates the Host is currently not connected. A Remote Host is +identified by its name if the name was supplied when the Remote Host was +added, otherwise the Remote Host is identified using its IPv4 address. + +Nodes may be Containerized (running in a Docker container) or +NonContainerized (running as a process on the host computer). The icon +for Containerized Nodes is a “bulls-eye”, whereas the icon for +NonContainerized Nodes is a singe solid circle. Both Containerized and +NonContainerized Nodes may be started on the Local Host, however, only +Containerized Nodes may be started on a Remote Host. + +The Node Manager displays only “Managed” Hosts and their Nodes. Managed +Hosts include the Local Host and any Remote Hosts which were added to +the Node Network by resolving their connectivity using SSH key-based +authentication. Managed Nodes include Containerized and NonContainerized +Nodes that were started by the Node Manager, as well as any +Containerized Nodes that were independently started (outside of the App) +on the Local Host or any of the currently connected Managed Remote +Hosts. + +Note that a Managed Remote Host may not be in a connected state at a +given point in time, and that no Nodes will be displayed for a +disconnected Remote Host. + +“Unmanaged” Nodes are Nodes which do not appear in the Node Manager +Network, but which may be connected to the active Server and displayed +in the SAGE Server App Network View Pane. These include NonContainerized +Nodes started outside of the App on the Local Host or a Remote Host, as +well as any Containerized Nodes running on an Unmanaged Remote Host. + +Node Manger Settings + +Clicking on the Settings button in the Node Manager menu brings up the +Node Manager Settings popup dialog. + +.. image:: _images/serverapp3/image17.png + :width: 4.52146in + :height: 4.40686in + +Node Manager settings include the following: + +- Default Node Scheduler Timer Precision. + +- Option to start a Local NonContainerized Node in a console window. + +- Node View Refresh Period to set the frequency for refreshing the Node + Network. + + - The Node Network can be refreshed manually at any time by clicking + on the Refresh button (curved arrow icon) on the Node Manager menu + strip. + +- Node Image Registry for pulling SAGE Docker images. + +Node Manager: Adding a Remote Host + +To add a Remote Host to the Node Network: + +1. Select the “SAGE Nodes” tree-node. + +2. Bring up the “SAGE Nodes” context menu by right-clicking on the SAGE + Nodes tree-node or left-clicking on the Manage menu button (icon with + three horizontal bars). + +3. Click the Add Managed Remote Host command. + +4. In the popup dialog, enter the Username and Host ID for logging onto + the remote host (using previously configured SSH key-based + authentication). + + - The Host ID can be either the name of the remote host or its IPv4 + address. + +5. Click the Test Connection button to resolve the Host ID. + +6. If the connection was successful, click Ok to confirm the command, or + Cancel to cancel the operation. + +|image6|\ |image7| + +In additon to the Add Managed Remote Host command, the “SAGE Nodes” +context menu also includes commands to Remove All Managed Remote Hosts +and Stop All Managed Nodes. The Node Manager always requests +confirmation before removing a Remote Host. + +** +** + +Node Manager: Removing a Remote Host + +To remove a Remote Host from the Node Network: + +1. Select the Remote Host tree-node. + +2. Bring up the Remote Host context menu by right-clicking on the Remote + Host tree-node or left-clicking on the Manage menu button. + +3. Click Remove Managed Host to remove the Remote Host. + +To remove all Managed Remote Hosts from the Node Network: + +- Select Remove All Managed Remote Hosts from the “SAGE Nodes” context + menu. + +The Node Manager will always request confirmation before removing a +Remote Host. + +Node Manager: Pulling a Docker Image to a Host + +Two conditions are required to start a Containerized Node on a Managed +Host: Docker must be installed and running, and the Docker sagenode +image for the current SAGE version (e.g., sagenode:3.0.2) must be +present on the Host. When a Host is selected in the Network Tree, the +Docker Running and Docker Image check boxes in the Information Pane +indicate if these conditions have been met. If Docker is running but the +sagenode image is missing, the Host context menu provides a command for +pulling the image from the Sage Node Image Repository specified in the +Settings dialog. + +To pull a Docker sagenode image: + +1. Select the Host tree-node. + +2. Bring up the Host context menu by right-clicking on the Host + tree-node or left-clicking on the Manage menu button. + +3. Click Pull Image to initiate the pull operation. + +.. image:: _images/serverapp3/image20.png + :width: 5.57292in + :height: 3.71468in + +The pull operation can be lengthy, especially if this is the first time +a sagenode image has been pulled to this Host. While the pull is in +progress the Host context menu provides a means of cancelling the +operation. When the pull is complete, the pull items are removed from +the context menu and the Docker Image checkbox will be checked. + +.. image:: _images/serverapp3/image21.png + :width: 5.56965in + :height: 3.72917in + +Node Manager: Starting a Node + +To start a Node on the Local Host or a Remote Host: + +1. Select the Host tree-node (Local Host or a Remote Host). + +2. Bring up the Host context menu by right-clicking on the Host + tree-node or left-clicking on the Manage menu button. + +3. Click Start Containerized Node to start a containerized Node, or + Start NonContainerized Node (Local Host only) to start a + nonContainerized Node. + + - Start Containerized Node is enabled if Docker is running and the + required Docker sagenode image is available on the Host system. + + - Start NonContainerized Node is available only on the Local Host + context menu and is enabled if SAGE Node is installed on the local + system. + +4. In the popup dialog, enter the Node name and select the desired + Scheduler Timer Precision (High, Medium or Low). + +5. Click Ok to confirm the command, or Cancel to cancel the operation. + +.. image:: _images/serverapp3/image22.png + :width: 3.53125in + :height: 5.10069in + +The newly created Node will appear beneath the Host tree-node in the +Network Tree. For a local nonContainerized Node, a SageNodeConsole +console window will be displayed on the desktop if that option was +enabled in the Node Manager settings. + +If the Server is active, the Node will connect to the Server and be +displayed in the SAGE Server App Network View Pane. If the Server is +inactive, the Node instance will connect after the Server is started. + +Node Manager: Stopping a Node + +To stop a Node on the Local Host or a Remote Host: + +1. Select the Node tree-node. + +2. Bring up the Node context menu by right-clicking on the Node + tree-node or left-clicking on the Manage menu button. + +3. Click Stop Node to initiate Node termination. + + - A NonContainerized Node will normally stop immediately, however, a + Containerized Node can take a number of seconds to stop. The icon + color changes to red to indicate that the Node is in the process + of terminating. Upon termination, the Node is removed from the + Node Network. + +To stop all Nodes on a single Host or the entire Network: + +- Select Stop All Managed Nodes on a Host context menu to stop all + Managed Nodes on that Host. + +- Select Stop All Managed Nodes on the “SAGE Nodes” context menu to + stop all Managed Nodes on the Network. + +** +** + +**The Behavior Manager** +======================== + +Use the Behavior Manager to view and update installed Behaviors. + +The Behavior Manager is opened by clicking on the Behavior Manager +button on the Server Toolstrip. + +.. image:: _images/serverapp3/image23.png + :width: 6.5in + :height: 4.34514in + +The Behavior Tree on the left shows the currently installed behavior +modules and their Behaviors. + +The Behavior Information Pane on the right contains information about a +Behavior when its corresponding tree-node is selected. + +Tree-nodes at the first three levels represent hierarchical colletions +of behavior module types, classified by language and target environment. + + Under Managed are the currently supported Managed Behavior Types: + “Java”, “JavaScript” and “Python”. + + Under Native are the currently supported Native Behavior Types: + “Linux32”, “Linux64”, “Windows32” and “Windows64” (32-bit and 64-bit + Windows and Linux modules). + +Under each Behavior Type tree-node are tree-nodes representing the +installed Behavior Modules for that type. + + The file extensions correspond to the Behavior Type, e.g., “.jar” for + Java, “.py” or “.egg” for Python, “.so” for Linux32 and Linux64, and + “.dll” for Windows32 and Windows64. + +Under each Behavior Module tree-node is the leaf tree-node representing +that module’s Behavior. When a Behavior tree-node is selected, +information about that Behavior is displayed in the Behavior Information +Pane. + +Management capabilities include adding and deleting Behavior Modules, +and refreshing the Behavior Tree to synchronize the Behavior Tree with +the SAGE Behavior repository. + +Behavior Manager: Adding a Behavior module + +To add a Behavior Module from the respoitory: + +1. Select an appropriate tree-node from one of the first three levels + (Behaviors, Managed, Native, or one of the Behavior Types). + + - Selecting a lower-level tree node restricts the types of modules + to add, e.g., selecting the Java Behavior Type will only allow + adding Java Behavior Modules. + +2. Bring up the associated context menu by right-clicking on the + selected tree-node or left-clicking on the Manage menu button (icon + with three horizontal lines). + +3. Click Add Module to display a File Open dialog. Navigate to the + desired folder and select one or more Behavior Module files to open. + +When a Behavior Module is added, the file is automatically added to the +proper SAGE Behavior repository sub-directory. + ++-----------------+----------------------------------------------------+ +| Behavior Type | Behavior Path | ++=================+====================================================+ +| Java | C:\\ProgramData\\Sage\\behaviors\\Java | ++-----------------+----------------------------------------------------+ +| JavaScript | C:\\ProgramData\\Sage\\behaviors\\JavaScript | ++-----------------+----------------------------------------------------+ +| Python | C:\\ProgramData\\Sage\\behaviors\\Python | ++-----------------+----------------------------------------------------+ +| Windows32 | C:\\ProgramData\\Sage\\behaviors\\Windows32 | ++-----------------+----------------------------------------------------+ +| Windows64 | C:\\ProgramData\\Sage\\behaviors\\Windows64 | ++-----------------+----------------------------------------------------+ +| Linux32 | C:\\ProgramData\\Sage\\behaviors\\Linux32 | ++-----------------+----------------------------------------------------+ +| Linux64 | C:\\ProgramData\\Sage\\behaviors\\Linux64 | ++-----------------+----------------------------------------------------+ + +Behavior Manager: Removing a Behavior module + +To remove a Behavior Module from the respoitory: + +1. Select the Behavior Module tree-node. + +2. Bring up the Behavior Module context menu by right-clicking on the + selected tree-node or left-clicking on the Manage menu button. + +3. Click Delete Module to remove the Behavior Module file from the SAGE + Behavior repository. + + - The Node Manager will request confirmation before completing the + action. + +Behavior Manager: Refreshing the Behavior Tree + +Click the Refresh Behavior Tree menu button (circular arrow icon) to +synchronize the behavior tree with the SAGE Behavior repository. This is +only required when behaviors are installed or uninstalled from the +repository outside of the App while the Behavior Manager window is open. + +The Behavior Tree is automatically refreshed whenever the Behavior +Manager is opened. + +The Behavior Manager is available when the Server is both active and +inactive and can remain open while the user interacts with the App’s +main form window. + + **Creating an Agent** +====================== + +Agents can be created on Nodes when the Server is active. + +To create an Agent on one or more Nodes: + +1. Select the Node(s) from the Server Toolstrip or Network View Pane. + + - Select a Node to create the Agent on just that Node. + + - Select (All Nodes) to create the Agent on all SAGE nodes. + +2. Click Create Agent from the Server Toolstrip or the Network View Pane + context menu. + +3. Enter the Agent’s name in the popup dialog. + +4. Click Ok to confirm the command, or Cancel to cancel the operation. + +.. image:: _images/serverapp3/image24.png + :width: 4.22976in + :height: 1.51063in + +If the agent already exists on a Node, the agent will not be created on +that Node. + +**Adding a Behavior to an Agent** +================================= + +Behaviors can be added to Agents when the Server is active. + +To add a Behavior to one or more Agents: + +1. Select the Agent(s) from the Server Toolstrip or Network View Pane. + + - Select an Agent to add the Behavior to just that Agent. + + - Select a Node to add the Behavior to all Agents of that Node. + + - Select (All Nodes) to add the Behavior to all Agents of all the + Nodes. + +2. Click Add Behavior from the Server Toolstrip or the Network View Pane + context menu. + +3. Select the Behavior from the Behavior Tree. + +4. Click Ok to confirm or Cancel to cancel the operation. + + - You can also confirm by right-clicking the Behavior and selecting + Select Behavior. + +.. image:: _images/serverapp3/image25.png + :width: 6.26042in + :height: 4.18498in + +If confirmed, the following popup dialog will appear: + +.. image:: _images/serverapp3/image26.png + :width: 3.97917in + :height: 3.54472in + +To specify topics for the Behavior: + +1. Enter the desired behavior topic strings. If topics have been added + to a previous Behavior, button Paste Previous Topics will be enabled. + Clicking this button will automatically add the previous topics to + this behavior. + +2. Click Ok to continue or Cancel to continue without adding a topic. + +If the behavior already belongs to an Agent, the behavior will not be +added to that Agent. + +**Viewing Behavior Properties** +=============================== + +To view the properties of a Behavior: + +1. Select the Behavior from the Server Toolstrip or the Network View + Pane. + +2. Click Show Properties from the Server Toolstrip or the Network View + Pane context menu. + +The Behavior Properties include the information provided by the Behavior +Manager as well as any Behavior Topics assigned when the Behavior was +added to the Agent. + +The Behavior Properties windows remains visible until the user closes it +or the Behavior becomes unselected in the Server Toolstrip or Network +View Pane. + +** +** + +**Removing a Behavior from an Agent** +===================================== + +Behaviors can be removed from Agents when the Server is active. + +To remove one or more Behaviors using the Remove command: + +1. Select the Behavior(s) from the Server Toolstrip or the Network View + Pane. + + - Select the Behavior to remove just that Behavior. + + - Select an Agent to remove all Behaviors from the Agent. + + - Select a Node to remove all Behaviors from all Agents of the Node. + + - Select (All Nodes) to remove all Behavior from all Agents of all + the Nodes. + +2. Click Remove from the Server Toolstrip or the Network View Pane + context menu. + +To remove one or more instances of a named Behavior using the Remove +Behavior command: + +1. Select the Agent(s) having the named Behavior from the Server + Toolstrip or the Network View Pane. + + - Select an Agent which has the named Behavior. + + - Select a Node having at least one Agent which has the named + Behavior. + + - Select (All Nodes) -- assumes a Network having at least one Agent + which has the named Behavior. + +2. Click Remove Behavior from the Server Toolstrip or the Network View + Pane context menu, then select the Behavior name from the popup combo + box. + +**Activating an Agent** +======================= + +Inactive agents can be activated when the Server is active. + +To activate one or more Agents using the Activate command: + +1. Select the Agent(s) from the Server Toolstrip or the Network View + Pane. + + - Select the Agent to activate just that Agent. + + - Select a Node to activate all Agents of that Node. + + - Select (All Nodes) to activate all Agents of all the Nodes. + +2. Click Activate from the Server Toolstrip or the Network View Pane + context menu. + +To activate one or more instances of a named Agent using the Activate +Agent command: + +1. Select the Node(s) having the named Agent from the Server Toolstrip + or the Network View Pane. + + - Select a Node which has the named Agent. + + - Select (All Nodes) -- assumes a Network having at least one Node + which has the named Agent. + +2. Click Activate Agent from the Server Toolstrip or the Network View + Pane context menu, then select the Agent name from the popup combo + box. + +**Deactivating an Agent** +========================= + +Active agents can be deactivated when the Server is active. + +To deactivate one or more Agents using the Deactivate command: + +1. Select the Agent(s) from the Server Toolstrip or the Network View + Pane. + + - Select the Agent to deactivate just that Agent. + + - Select a Node to deactivate all Agents of that Node. + + - Select (All Nodes) to deactivate all Agents of all the Nodes. + +2. Click Deactivate from the Server Toolstrip or the Network View Pane + context menu. + +To deactivate one or more instances of a named Agent using the +Deactivate Agent command: + +1. Select the Node(s) having the named Agent from the Server Toolstrip + or the Network View Pane. + + - Select a Node which has the named Agent. + + - Select (All Nodes) -- assumes a Network havnig at least one Node + which has the named Agent. + +2. Click Deactivate Agent from the Server Toolstrip or the Network View + Pane context menu, then select the Agent name from the popup combo + box. + +**Sending a Message** +===================== + +The Send Message command allows the user to send a message from the SAGE +server to one or more Nodes and their Agents when the Server is active. + +To send a message: + +1. Select the target Node(s) and Agents(s) from the Server Toolstrip or + the Network View Pane. + + - Select an Agent to send a message to just the Agent and its Node. + + - Select a Node to send a message to the Node and all its Agents. + + - Select (All Nodes) to send a message to all the Nodes and all + their Agents. + +2. Click Send Message from the Server Toolstrip or the Network View Pane + context menu. + +3. In the Send Message dialog, enter the message text, topic and any + data items. + +4. Click Ok to confirm, or Cancel to cancel the operation. + +.. image:: _images/serverapp3/image27.png + :width: 3.6113in + :height: 5.16667in + +Message sending is graphically depicted in the Network Graph View. +Messages are shown traveling from the source (in this case the Server) +to one or more destinations (in this case Node1 and all its Agents). + +.. image:: _images/serverapp3/image28.png + :width: 6.5in + :height: 5.68056in + +The source entity is highlighted with a large rectangle and the +destination entity are highlighted with small rectangles. + +Server messages (generated using the Send Message command) are shown in +orange. + +Agent messages (generated by agent Behaviors) are shown in light blue. + +** +** + +**Sending Files to a Node** +=========================== + +The Send File command allows the user to send a file from the SAGE +server to one or more Nodes when the Server is active. + +To send a file: + +1. Select the Node(s) from the Server Toolstrip or the Network View + Pane. + + - Select a Node to send the file to just that Node. + + - Select (All Nodes) to send a file to all the Nodes. + +2. Click Send File from the Server Toolstrip or the Network View Pane + context menu. + +3. Navigate to the desired folder and select the file to send. + +4. Click Open to confirm, or Cancel to cancel the operation. + +A sub-folder with the same name as the Node will be created (if it does +not already exist) in the SAGE data directory on the targeted Node +machine where the sent files will be copied to. + +“\ *C:\\ProgramData\\Sage\\data\\NodeName”* + +**Viewing Agent State Spaces** +============================== + +Every SAGE agent has a State Space which includes the following +information: + +- Agent name + +- Node name + +- The “sageHome” directory + +- The “sageNodeHome” directory + +An active Agent can have additional named States which are created and +managed by one or more of its Behaviors. + +To view the State Space for one or more Agents: + +1. Select the Agent(s) from the Server Toolstrip or Network View Pane. + + - Select an Agent to view its State Space. + + - Select a Node to display the State Spaces of all Agents on the + Node. + + - Select (All Nodes) to display the State Spaces of all Agents on + all SAGE nodes. + +2. Click Show State Space from the Server Toolstrip or the Network View + Pane context menu. + + - If the State Space is already open, this will bring it to the + foreground. + +The Agent State Space below shows a number of additional states which +were created and are dynamically managed by the Agent’s Behavior. + +.. image:: _images/serverapp3/image29.png + :width: 6.49049in + :height: 5.50077in + +To hide open Agent State Space(s), either click the State Space window’s +Close button or do the following: + +1. Select the Agent(s) from the Server Toolstrip or Network View Pane. + + - Select an Agent to hide its State Space. + + - Select a Node to hide the State Spaces of all Agents on the Node. + + - Select (All Nodes) to hide the State Spaces of all Agents on all + SAGE nodes in the foreground. + +2. Click Hide State Space from the Server Toolstrip or the Network View + Pane context menu. + +**The SAGE Robot Interface** +============================ + +The SAGE Robot Interface allows you to run Robot scripts and view the +results from within the SAGE Server App. + +Click the Robot Interface button on the Server Toolstrip to start a new +instance of the SAGE Robot Interface, as shown below. + +.. image:: _images/serverapp3/image30.png + :width: 6.5in + :height: 7.69931in + +At the top of the window are controls to select and sequence the Robot +script files. + +Robot scripts are added, removed and sequenced using the buttons to the +right of the Robot scripts list. + +The Add and Remove operations are also available from the File menu. + +To run a Robot script: + +1. Open Robot Interface + +2. Click the Add button . + +3. Select the Robot file and click Open. + +4. Repeat steps 1 and 2 to add additional Robot scripts. + +5. Click the Start button to start the run. + +The Robot scripts will be run one at a time in the sequence specified. + +Clicking the Stop button will abort the run. + +When a Robot script successfully completes, the pathname of the +generated report file appears in the report list at the bottom of the +window. + +.. image:: _images/serverapp3/image31.png + :width: 6.5in + :height: 7.69931in + +To view a report, select it from the report list and click the Report +button located in the bottom-right corner. You may also right-click the +report pathname and select View Report from the context menu. + +**The Log Viewer** +================== + +The display of Server-generated log events are handled by the Log +Viewer. + +The types of log events include exceptions, errors, warning, +informational messages, and behavior execution results. + +By default a single-line header is displayed showing the timestamp, +event type, and a brief description. + +.. image:: _images/serverapp3/image32.png + :width: 6.5in + :height: 5.93681in + +Message and result events can be expanded to show additional +information. + +Only one log event can be expanded at a time. + +The Logger Toolstrip provides buttons for copying log events to the +Windows clipboard and for clearing the Log Viewer. These commands are +also available on the context menu displayed when right-clicking on a +log event. + +When the Server is stopped, currently displayed event logs remain. + +All events, including removed events, are saved to a log data file +located in *C:\\ProgramData\\SAGE\\logs*. + +**Loading and Saving an Agent Network** +======================================= + +Agent network configurations can be saved and loaded. The files are +saved as two JSON files with a common base filename and the extensions +“.sage” and “.sagenode”. + +- The Node Network JSON file has extension “.sagenode” and is used by + the SAGE Node Manager to start the Managed Nodes. + + - Node networks can be independently loaded and saved from the Node + Manager using the Load Managed Nodes and Save Managed Nodes + menu buttons, even when the Server is inactive. + +- The Agent Network JSON file has extension “.sage” is used by the SAGE + Server to load the Agents and their Behaviors on the connected Nodes. + + - This is the file that the user sees when loading or saving an + Agent Network from the App. It will always be accompanied by + the companion “.sagenode” file used by the Node Manager to + start the Nodes. + +**Saving an Agent Network** + +The current Agent network configuration can be saved (exported) when the +Server is active. + +To save an Agent network: + +1. Click the Save Network button on the Control Toolstrip. + +2. Navigate to the desired folder for saving the network configuration + files. + +3. Enter a filename for your Agent Network configuration (must have + extension “.sage”). + +4. Click the Save button. + +**Loading an Agent Network** + +A previously saved network configuration can be loaded (imported) when +the Server is inactive. + +To load an Agent network: + +1. Click the Load Network button on the Control Toolstrip. + +2. Navigate to the folder containing the previously saved network + configuration files and select the Agent Network file (with extension + “.sage”). + +3. Click the Open button. + +The SAGE Server will start and the Node Manager will attempt to start +any missing Nodes. The Server will then perform a validation check on +the JSON tree by ensuring that all Nodes referenced in the network exist +and that all Behaviors to be added to the Agents exists in the Behavior +repository. + +If there are any errors (e.g., missing Nodes or Behaviors), an “Agent +Network Load Errors” dialog window will appear listing the errors. + +The dialog window remains open while the user attempts to resolve the +issues. + +.. image:: _images/serverapp3/image33.png + :width: 6.5in + :height: 5.67431in + +In the above example, two Nodes residing on the remote Host named +“surface-laptop” could not be started because the remote Host was +offline. The issue is resolved by bringing “surface-laptop” back online. + +Click the Retry button to retry loading the network configuration, or +click Cancel to abort the operation. + +If there are no more errors, the Server is able to create the Agents and +load their Behaviors so that the saved network is fully configured. + +.. image:: _images/serverapp3/image34.png + :width: 6.5in + :height: 5.77917in + +.. |image1| image:: _images/serverapp3/image6.png + :width: 6.5in + :height: 5.92569in +.. |image2| image:: _images/serverapp3/image9.png + :width: 3.19792in + :height: 2.73701in +.. |image3| image:: _images/serverapp3/image10.png + :width: 3.09375in + :height: 2.72168in +.. |image4| image:: _images/serverapp3/image13.png + :width: 3.23891in + :height: 3.23194in +.. |image5| image:: _images/serverapp3/image14.png + :width: 3.21875in + :height: 3.23274in +.. |image6| image:: _images/serverapp3/image18.png + :width: 2.99283in + :height: 3.89583in +.. |image7| image:: _images/serverapp3/image19.png + :width: 2.95833in + :height: 3.87056in diff --git a/docs/_build/html/_sources/sage_app.rst.txt b/docs/_build/html/_sources/sage_app.rst.txt new file mode 100644 index 0000000..7630eeb --- /dev/null +++ b/docs/_build/html/_sources/sage_app.rst.txt @@ -0,0 +1,1241 @@ +**SAGE Server Application** +=========================== + +The SAGE Server App provides a graphical user interface for viewing and +controlling the SAGE runtime environment. SAGE Server App supports the +following functions: + +- Manage behavior modules + +- Start and stop the SAGE server + +- View connected nodes + +- Manage nodes on the local server machine and networked remote + machines + +- Control node access to the server machine + +- Send files and messages to nodes + +- Create, activate, deactivate and remove agents + +- Send messages to agents + +- Add and remove agent behaviors + +- Select, sequence and run SAGE Robot files + +- View generated Robot reports + +- View SAGE server log output, including behavior execution results + +- Load and Save SAGE networks + +SAGE Server App is Windows compatible and distributed with the Windows +x64 - Server installer. + +To run SAGE Server App, double-click on the shortcut icon, or +right-click on the icon and select “Open” from the context menu. + +**Main Window** +=============== + +Following is an annotated view of the SAGE Server App window when the +application opens. + +.. image:: _images/serverapp/image1.png + :width: 6.5in + :height: 6.5375in + +Control Toolstrip + +Provides buttons for: + +- Starting and stopping the SAGE Server. + +- Loading and Saving a SAGE network. + +- Configuring Server settings. + +- Displaying information about the SAGE Server and App. + +Server Toolstrip + +Provides buttons for viewing and controlling the SAGE network: + +- Manage SAGE Nodes on the local Server machine and networked remote + machines. + +- Manage SAGE Behaviors + +- Launch the SAGE Robot Interface + +- Create and remove Agents + +- Activate and deactivate Agents. + +- Add and remove Behaviors + +- View Behavior properties. + +- Send files to Nodes. + +- Send messages to Nodes and Agents. + +- View Agent State Space + +Network View Pane + +Allows you to view and control the SAGE network using the following +views: + +- Network Tree View + +- Network Graph View + +Views can be toggled by clicking on the respective tab. + +Logger Toolstrip + +Allows you to interact with server-generated log events. + +Provides buttons for: + +- Copying event logs to the Windows clipboard. + +- Clearing logs displayed in the Logger View Pane. + +- Controlling the scrolling of log events when the server is active. + +Logger View Pane + +Allows you to view server-generated log events, including behavior +execution results as they occur in real-time. + +**Server Settings** +=================== + +Clicking on the Settings button in the Control Toolstrip brings up the +Server Settings popup dialog. + +.. image:: _images/serverapp/image2.png + :width: 6.5in + :height: 4.725in + +SAGE Server settings include the following: + +- Control Node access to the server machine. + +- Set Server IP port number + +- Set the maximum capacity of the SAGE event logger. + +- Adjusting window overlays. + +- Changing color theme of application. + +Node access control is enforced when Enable Node Access Control is +checked. This allows you to whitelist IP addresses in dot-decimal +notation. An asterisk may be used as a wildcard character for any of the +octet-grouped decimal numbers. Only IP addresses listed are allowed to +connect to the server. + +Setting the maximum capacity of the event logger prevents +Server-generated log events from overrunning memory when the Server runs +for very long periods of time (day or even weeks). When the maximum +capacity is reached, older events are removed to make room for new +events. + +Settings are automatically saved when the application terminates. + +**Network Tree View** +===================== + +The Network Tree View provides a tree view of the SAGE network when the +Server is active. + +- The root of the network tree is the NodeRoot tree-node representing + the set of all connected SAGE Nodes. + +- SAGE Nodes are shown as branches under the NodeRoot tree-node. Each + Node has an Agents tree-node representing the set of all Agents + belonging to the Node. + +- A Node’s Agents are shown as branches under the Agents tree-node. + Each Agent has a Behaviors tree-node representing the set of all + Behaviors belonging to the Agent. + +- An Agent’s Behaviors are shown as leaf tree-nodes under the Behaviors + tree-node. + +Clicking on any tree-node selects and highlights it. Tree-nodes +representing ancestor network entities are also selected. + +Right-clicking on a tree-node displays a set of cascading context menus +with a set of commands relevant to the current selection. + +You can expand and collapse tree-nodes by clicking on the plus or minus +sign next to a tree-node branch. + +Double-clicking on a tree-node fully expands a branch if it is +collapsed, and fully collapses a branch if it is expanded. + +.. image:: _images/serverapp/image3.png + :width: 6.5in + :height: 5.92569in + +**Network Graph View** +====================== + +The Network Graph View provides a dynamic graph display of the SAGE +network when the Server is active. + +- The Server graph-node represents the SAGE Server and is always + visible when the Server is active. + +- SAGE Nodes are shown as root graph-nodes of their own sub-graphs. + +- Graph-nodes representing Agents are connected to their Node + graph-node, and graph-nodes representing Behaviors are connected to + their Agent graph-node. + +Clicking on any graph-node selects and highlights it. Graph-nodes +representing ancestor network entities are also selected. + +Right-clicking on a graph-node displays a set of cascading context menus +with a set of commands relevant to the selected object. + +Clicking on the Server graph-node or on the view background displays a +context menu relevant to the entire network. + +You can reposition entities within the graph region by dragging with the +left mouse button. + +Double-clicking on a graph-node centers the entity within the view pane. + +Double-clicking on the view background centers the graph region about +that position in the view pane. + +The graph view can be panned by clicking down anywhere in the view pane +that is not on a graph-node and dragging. + +.. image:: _images/serverapp/image4.png + :width: 6.5in + :height: 5.92569in + +The graph view can be zoomed out and back in using the mouse wheel. When +zooming, the scaling is applied about the mouse cursor position. + +.. image:: _images/serverapp/image5.png + :width: 6.5in + :height: 5.92569in + +**Starting the Server** +======================= + +Click the Start button or the Load Network button in the Control +Toolstrip to start the Server instance. After the Server has started, +any previously created Nodes will be connected and displayed in the +Network View Pane. + +If the Server is started using the Load Network button, a previously +saved Agent network is loaded. Nodes specified in the Agent network +which are not already running will be started. + +Once the Server becomes active, the Start button changes to a Stop +button and the Load Network button changes to a Save Network button. The +Server can be stopped at any time by clicking the Stop button. + +**Active Server** +================= + +When the Server is active, the current state of the network is reflected +in the Server Toolstrip and the Network View Pane. + +The following screenshot shows an active Server network, with the +Network Tree View displayed in the view pane. |image1| + +Clicking on the Network Graph View tab displays a graph-based view of +the network. + +.. image:: _images/serverapp/image7.png + :width: 6.5in + :height: 5.92569in + +Nodes, their Agents and agent Behaviors are selected using either the +ServerToolstrip or Network View Pane. + +Commands operate on the current selection and are accessible from either +the Server Toolstrip or Network View Pane context menus. + +On the Server Toolstrip, node-related commands are under the Node +dropdown button, agent-related commands are under the Agent dropdown +button, and behavior-related commands are under the Behavior dropdown +button. + +.. image:: _images/serverapp/image8.png + :width: 5.4253in + :height: 6.71875in + +When an individual Node, Agent or Behavior is not selected, the +corresponding dropdown button will display “(All Nodes)”, “(All +Agents)”, or “(All Behaviors)”, and the commands will apply to all +objects of that type. + +In the image above, clicking the agent Activate button on the Server +Toolstrip activates all inactive agents on all nodes in the network. + +The image below shows how to perform the same operation using the +Network View Pane: + +1. Right-click on one of the following to display the Network View Pane + context menu: + +- NodeRoot in the Network Tree View. + +- The Server graph-node in the Network Graph View. + +- The panel background in the Network Graph View. + +2. Move the mouse over (All Nodes) to display the cascading node context + menu. + +3. Move the mouse over (All Agents) to display the cascading agent + context menu. + +4. Click the Activate button on the agent context menu. + +|image2|\ |image3| + +Notice that commands in the cascading context menus match the commands +in the Server Toolstrip. + +In the Network Graph View, icons representing the newly activated Agents +change color from red (inactive) to green (active), and dynamic +messaging lines show the flow of messages sent between Agents. + +.. image:: _images/serverapp/image11.png + :width: 6.5in + :height: 5.875in + +Click on the agent Deactivate button to deactivate all the Agents. + +**Selecting a SAGE Node, Agent or Behavior** + +A SAGE object (Node, Agent or Behavior) can be selected from the Server +Toolstrip or the Network View Pane. + +To select a Node, Agent or Behavior from the Network View Pane, click on +the corresponding tree-node or graph-node. + +To select a Node, Agent or Behavior from the Server Toolstrip, click on +the corresponding dropdown button and select the object’s name from the +popup combo box, as shown below. + +.. image:: _images/serverapp/image12.png + :width: 3.89638in + :height: 4.7715in + +The current selection is reflected in both the Server Toolstrip and +Network View Pane (Tree View or Graph View). + +The mechanism for selecting SAGE objects and applying commands is +enforced by the topology of the Network Tree View and Graph View and by +the Server Toolstrip menu items. + +In the screen shot below, NodeFive is selected, but no Agent or Behavior +has been selected. + +- The node-related commands apply to NodeFive. + +- The agent-related commands apply to all the NodeFive Agents. + +- The behavior-related commands apply to all the Behaviors on all the + NodeFive Agents. + +|image4|\ |image5| + +The Server Toolstrip can be very useful when managing networks with a +large number of Nodes or Agents. + +In the following screenshot, the network has a single Node with 50 +Agents. Selecting an Agent using the Server Toolstrip is much easier +than trying to locate and select the Agent using either of the Network +Views. + +.. image:: _images/serverapp/image15.png + :width: 6.5in + :height: 4.10208in + +The number of Agent names to scroll through in the toolstrip combo box +can be reduced by entering the first few letters of the name (e.g. “A2”) +in the combo box edit control. + +**The Node Manager** +==================== + +Use the SAGE Node Manager to start and stop Containerized and +NonContainerized Nodes on the Local Host computer, and containerized +nodes on networked Remote Host computers. SAGE Nodes can be started and +stopped at any time, even when the Server is inactive. + +The Node Manager is opened by clicking on the Node Manager button on the +Server Toolstrip or the Network View Pane context menu (when selecting +the NodeRoot in the Tree View or the Server graph-node or panel +background in the Graph View) . + +.. image:: _images/serverapp/image16.png + :width: 6.5in + :height: 4.34236in + +The Network Tree at the left displays the current host network (the +Local Host and any managed Remote Hosts) and the SAGE nodes running on +each Host. The Information Pane at the right displays information about +the selected Node or Host tree-node. + +A Host is in the connected state if its icon is blue; a gray icon +indicates the Host is currently not connected. A Remote Host is +identified by its name if the name was supplied when the Remote Host was +added, otherwise the Remote Host is identified using its IPv4 address. + +Nodes may be Containerized (running in a Docker container) or +NonContainerized (running as a process on the host computer). The icon +for Containerized Nodes is a “bulls-eye”, whereas the icon for +NonContainerized Nodes is a singe solid circle. Both Containerized and +NonContainerized Nodes may be started on the Local Host, however, only +Containerized Nodes may be started on a Remote Host. + +The Node Manager displays only “Managed” Hosts and their Nodes. Managed +Hosts include the Local Host and any Remote Hosts which were added to +the Node Network by resolving their connectivity using SSH key-based +authentication. Managed Nodes include Containerized and NonContainerized +Nodes that were started by the Node Manager, as well as any +Containerized Nodes that were independently started (outside of the App) +on the Local Host or any of the currently connected Managed Remote +Hosts. + +Note that a Managed Remote Host may not be in a connected state at a +given point in time, and that no Nodes will be displayed for a +disconnected Remote Host. + +“Unmanaged” Nodes are Nodes which do not appear in the Node Manager +Network, but which may be connected to the active Server and displayed +in the SAGE Server App Network View Pane. These include NonContainerized +Nodes started outside of the App on the Local Host or a Remote Host, as +well as any Containerized Nodes running on an Unmanaged Remote Host. + +Node Manger Settings + +Clicking on the Settings button in the Node Manager menu brings up the +Node Manager Settings popup dialog. + +.. image:: _images/serverapp/image17.png + :width: 4.52146in + :height: 4.40686in + +Node Manager settings include the following: + +- Default Node Scheduler Timer Precision. + +- Option to start a Local NonContainerized Node in a console window. + +- Node View Refresh Period to set the frequency for refreshing the Node + Network. + + - The Node Network can be refreshed manually at any time by clicking + on the Refresh button (curved arrow icon) on the Node Manager menu + strip. + +- Node Image Registry for pulling SAGE Docker images. + +Node Manager: Adding a Remote Host + +To add a Remote Host to the Node Network: + +1. Select the “SAGE Nodes” tree-node. + +2. Bring up the “SAGE Nodes” context menu by right-clicking on the SAGE + Nodes tree-node or left-clicking on the Manage menu button (icon with + three horizontal bars). + +3. Click the Add Managed Remote Host command. + +4. In the popup dialog, enter the Username and Host ID for logging onto + the remote host (using previously configured SSH key-based + authentication). + + - The Host ID can be either the name of the remote host or its IPv4 + address. + +5. Click the Test Connection button to resolve the Host ID. + +6. If the connection was successful, click Ok to confirm the command, or + Cancel to cancel the operation. + +|image6|\ |image7| + +In additon to the Add Managed Remote Host command, the “SAGE Nodes” +context menu also includes commands to Remove All Managed Remote Hosts +and Stop All Managed Nodes. The Node Manager always requests +confirmation before removing a Remote Host. + +** +** + +Node Manager: Removing a Remote Host + +To remove a Remote Host from the Node Network: + +1. Select the Remote Host tree-node. + +2. Bring up the Remote Host context menu by right-clicking on the Remote + Host tree-node or left-clicking on the Manage menu button. + +3. Click Remove Managed Host to remove the Remote Host. + +To remove all Managed Remote Hosts from the Node Network: + +- Select Remove All Managed Remote Hosts from the “SAGE Nodes” context + menu. + +The Node Manager will always request confirmation before removing a +Remote Host. + +Node Manager: Pulling a Docker Image to a Host + +Two conditions are required to start a Containerized Node on a Managed +Host: Docker must be installed and running, and the Docker sagenode +image for the current SAGE version (e.g., sagenode:3.0.3) must be +present on the Host. When a Host is selected in the Network Tree, the +Docker Running and Docker Image check boxes in the Information Pane +indicate if these conditions have been met. If Docker is running but the +sagenode image is missing, the Host context menu provides a command for +pulling the image from the Sage Node Image Repository specified in the +Settings dialog. + +To pull a Docker sagenode image: + +1. Select the Host tree-node. + +2. Bring up the Host context menu by right-clicking on the Host + tree-node or left-clicking on the Manage menu button. + +3. Click Pull Image to initiate the pull operation. + +.. image:: _images/serverapp/image20.png + :width: 5.57292in + :height: 3.71468in + +The pull operation can be lengthy, especially if this is the first time +a sagenode image has been pulled to this Host. While the pull is in +progress the Host context menu provides a means of cancelling the +operation. When the pull is complete, the pull items are removed from +the context menu and the Docker Image checkbox will be checked. + +.. image:: _images/serverapp/image21.png + :width: 5.56965in + :height: 3.72917in + +Node Manager: Starting a Node + +To start a Node on the Local Host or a Remote Host: + +1. Select the Host tree-node (Local Host or a Remote Host). + +2. Bring up the Host context menu by right-clicking on the Host + tree-node or left-clicking on the Manage menu button. + +3. Click Start Containerized Node to start a containerized Node, or + Start NonContainerized Node (Local Host only) to start a + nonContainerized Node. + + - Start Containerized Node is enabled if Docker is running and the + required Docker sagenode image is available on the Host system. + + - Start NonContainerized Node is available only on the Local Host + context menu and is enabled if SAGE Node is installed on the local + system. + +4. In the popup dialog, enter the Node name and select the desired + Scheduler Timer Precision (High, Medium or Low). + +5. Click Ok to confirm the command, or Cancel to cancel the operation. + +.. image:: _images/serverapp/image22.png + :width: 3.53125in + :height: 5.10069in + +The newly created Node will appear beneath the Host tree-node in the +Network Tree. For a local nonContainerized Node, a SageNodeConsole +console window will be displayed on the desktop if that option was +enabled in the Node Manager settings. + +If the Server is active, the Node will connect to the Server and be +displayed in the SAGE Server App Network View Pane. If the Server is +inactive, the Node instance will connect after the Server is started. + +Node Manager: Stopping a Node + +To stop a Node on the Local Host or a Remote Host: + +1. Select the Node tree-node. + +2. Bring up the Node context menu by right-clicking on the Node + tree-node or left-clicking on the Manage menu button. + +3. Click Stop Node to initiate Node termination. + + - A NonContainerized Node will normally stop immediately, however, a + Containerized Node can take a number of seconds to stop. The icon + color changes to red to indicate that the Node is in the process + of terminating. Upon termination, the Node is removed from the + Node Network. + +To stop all Nodes on a single Host or the entire Network: + +- Select Stop All Managed Nodes on a Host context menu to stop all + Managed Nodes on that Host. + +- Select Stop All Managed Nodes on the “SAGE Nodes” context menu to + stop all Managed Nodes on the Network. + +** +** + +**The Behavior Manager** +======================== + +Use the Behavior Manager to view and update installed Behaviors. + +The Behavior Manager is opened by clicking on the Behavior Manager +button on the Server Toolstrip. + +.. image:: _images/serverapp/image23.png + :width: 6.5in + :height: 4.34514in + +The Behavior Tree on the left shows the currently installed behavior +modules and their Behaviors. + +The Behavior Information Pane on the right contains information about a +Behavior when its corresponding tree-node is selected. + +Tree-nodes at the first three levels represent hierarchical colletions +of behavior module types, classified by language and target environment. + + Under Managed are the currently supported Managed Behavior Types: + “Java”, “JavaScript” and “Python”. + + Under Native are the currently supported Native Behavior Types: + “Linux32”, “Linux64”, “Windows32” and “Windows64” (32-bit and 64-bit + Windows and Linux modules). + +Under each Behavior Type tree-node are tree-nodes representing the +installed Behavior Modules for that type. + + The file extensions correspond to the Behavior Type, e.g., “.jar” for + Java, “.py” or “.egg” for Python, “.so” for Linux32 and Linux64, and + “.dll” for Windows32 and Windows64. + +Under each Behavior Module tree-node is the leaf tree-node representing +that module’s Behavior. When a Behavior tree-node is selected, +information about that Behavior is displayed in the Behavior Information +Pane. + +Management capabilities include adding and deleting Behavior Modules, +and refreshing the Behavior Tree to synchronize the Behavior Tree with +the SAGE Behavior repository. + +Behavior Manager: Adding a Behavior module + +To add a Behavior Module from the respoitory: + +1. Select an appropriate tree-node from one of the first three levels + (Behaviors, Managed, Native, or one of the Behavior Types). + + - Selecting a lower-level tree node restricts the types of modules + to add, e.g., selecting the Java Behavior Type will only allow + adding Java Behavior Modules. + +2. Bring up the associated context menu by right-clicking on the + selected tree-node or left-clicking on the Manage menu button (icon + with three horizontal lines). + +3. Click Add Module to display a File Open dialog. Navigate to the + desired folder and select one or more Behavior Module files to open. + +When a Behavior Module is added, the file is automatically added to the +proper SAGE Behavior repository sub-directory. + ++-----------------+----------------------------------------------------+ +| Behavior Type | Behavior Path | ++=================+====================================================+ +| Java | C:\\ProgramData\\Sage\\behaviors\\Java | ++-----------------+----------------------------------------------------+ +| JavaScript | C:\\ProgramData\\Sage\\behaviors\\JavaScript | ++-----------------+----------------------------------------------------+ +| Python | C:\\ProgramData\\Sage\\behaviors\\Python | ++-----------------+----------------------------------------------------+ +| Windows32 | C:\\ProgramData\\Sage\\behaviors\\Windows32 | ++-----------------+----------------------------------------------------+ +| Windows64 | C:\\ProgramData\\Sage\\behaviors\\Windows64 | ++-----------------+----------------------------------------------------+ +| Linux32 | C:\\ProgramData\\Sage\\behaviors\\Linux32 | ++-----------------+----------------------------------------------------+ +| Linux64 | C:\\ProgramData\\Sage\\behaviors\\Linux64 | ++-----------------+----------------------------------------------------+ + +Behavior Manager: Removing a Behavior module + +To remove a Behavior Module from the respoitory: + +1. Select the Behavior Module tree-node. + +2. Bring up the Behavior Module context menu by right-clicking on the + selected tree-node or left-clicking on the Manage menu button. + +3. Click Delete Module to remove the Behavior Module file from the SAGE + Behavior repository. + + - The Node Manager will request confirmation before completing the + action. + +Behavior Manager: Refreshing the Behavior Tree + +Click the Refresh Behavior Tree menu button (circular arrow icon) to +synchronize the behavior tree with the SAGE Behavior repository. This is +only required when behaviors are installed or uninstalled from the +repository outside of the App while the Behavior Manager window is open. + +The Behavior Tree is automatically refreshed whenever the Behavior +Manager is opened. + +The Behavior Manager is available when the Server is both active and +inactive and can remain open while the user interacts with the App’s +main form window. + + **Creating an Agent** +====================== + +Agents can be created on Nodes when the Server is active. + +To create an Agent on one or more Nodes: + +1. Select the Node(s) from the Server Toolstrip or Network View Pane. + + - Select a Node to create the Agent on just that Node. + + - Select (All Nodes) to create the Agent on all SAGE nodes. + +2. Click Create Agent from the Server Toolstrip or the Network View Pane + context menu. + +3. Enter the Agent’s name in the popup dialog. + +4. Click Ok to confirm the command, or Cancel to cancel the operation. + +.. image:: _images/serverapp/image24.png + :width: 4.22976in + :height: 1.51063in + +If the agent already exists on a Node, the agent will not be created on +that Node. + +**Adding a Behavior to an Agent** +================================= + +Behaviors can be added to Agents when the Server is active. + +To add a Behavior to one or more Agents: + +1. Select the Agent(s) from the Server Toolstrip or Network View Pane. + + - Select an Agent to add the Behavior to just that Agent. + + - Select a Node to add the Behavior to all Agents of that Node. + + - Select (All Nodes) to add the Behavior to all Agents of all the + Nodes. + +2. Click Add Behavior from the Server Toolstrip or the Network View Pane + context menu. + +3. Select the Behavior from the Behavior Tree. + +4. Click Ok to confirm or Cancel to cancel the operation. + + - You can also confirm by right-clicking the Behavior and selecting + Select Behavior. + +.. image:: _images/serverapp/image25.png + :width: 6.26042in + :height: 4.18498in + +If confirmed, the following popup dialog will appear: + +.. image:: _images/serverapp/image26.png + :width: 3.97917in + :height: 3.54472in + +To specify topics for the Behavior: + +1. Enter the desired behavior topic strings. If topics have been added + to a previous Behavior, button Paste Previous Topics will be enabled. + Clicking this button will automatically add the previous topics to + this behavior. + +2. Click Ok to continue or Cancel to continue without adding a topic. + +If the behavior already belongs to an Agent, the behavior will not be +added to that Agent. + +**Viewing Behavior Properties** +=============================== + +To view the properties of a Behavior: + +1. Select the Behavior from the Server Toolstrip or the Network View + Pane. + +2. Click Show Properties from the Server Toolstrip or the Network View + Pane context menu. + +The Behavior Properties include the information provided by the Behavior +Manager as well as any Behavior Topics assigned when the Behavior was +added to the Agent. + +The Behavior Properties windows remains visible until the user closes it +or the Behavior becomes unselected in the Server Toolstrip or Network +View Pane. + +** +** + +**Removing a Behavior from an Agent** +===================================== + +Behaviors can be removed from Agents when the Server is active. + +To remove one or more Behaviors using the Remove command: + +1. Select the Behavior(s) from the Server Toolstrip or the Network View + Pane. + + - Select the Behavior to remove just that Behavior. + + - Select an Agent to remove all Behaviors from the Agent. + + - Select a Node to remove all Behaviors from all Agents of the Node. + + - Select (All Nodes) to remove all Behavior from all Agents of all + the Nodes. + +2. Click Remove from the Server Toolstrip or the Network View Pane + context menu. + +To remove one or more instances of a named Behavior using the Remove +Behavior command: + +1. Select the Agent(s) having the named Behavior from the Server + Toolstrip or the Network View Pane. + + - Select an Agent which has the named Behavior. + + - Select a Node having at least one Agent which has the named + Behavior. + + - Select (All Nodes) -- assumes a Network having at least one Agent + which has the named Behavior. + +2. Click Remove Behavior from the Server Toolstrip or the Network View + Pane context menu, then select the Behavior name from the popup combo + box. + +**Activating an Agent** +======================= + +Inactive agents can be activated when the Server is active. + +To activate one or more Agents using the Activate command: + +1. Select the Agent(s) from the Server Toolstrip or the Network View + Pane. + + - Select the Agent to activate just that Agent. + + - Select a Node to activate all Agents of that Node. + + - Select (All Nodes) to activate all Agents of all the Nodes. + +2. Click Activate from the Server Toolstrip or the Network View Pane + context menu. + +To activate one or more instances of a named Agent using the Activate +Agent command: + +1. Select the Node(s) having the named Agent from the Server Toolstrip + or the Network View Pane. + + - Select a Node which has the named Agent. + + - Select (All Nodes) -- assumes a Network having at least one Node + which has the named Agent. + +2. Click Activate Agent from the Server Toolstrip or the Network View + Pane context menu, then select the Agent name from the popup combo + box. + +**Deactivating an Agent** +========================= + +Active agents can be deactivated when the Server is active. + +To deactivate one or more Agents using the Deactivate command: + +1. Select the Agent(s) from the Server Toolstrip or the Network View + Pane. + + - Select the Agent to deactivate just that Agent. + + - Select a Node to deactivate all Agents of that Node. + + - Select (All Nodes) to deactivate all Agents of all the Nodes. + +2. Click Deactivate from the Server Toolstrip or the Network View Pane + context menu. + +To deactivate one or more instances of a named Agent using the +Deactivate Agent command: + +1. Select the Node(s) having the named Agent from the Server Toolstrip + or the Network View Pane. + + - Select a Node which has the named Agent. + + - Select (All Nodes) -- assumes a Network havnig at least one Node + which has the named Agent. + +2. Click Deactivate Agent from the Server Toolstrip or the Network View + Pane context menu, then select the Agent name from the popup combo + box. + +**Sending a Message** +===================== + +The Send Message command allows the user to send a message from the SAGE +server to one or more Nodes and their Agents when the Server is active. + +To send a message: + +1. Select the target Node(s) and Agents(s) from the Server Toolstrip or + the Network View Pane. + + - Select an Agent to send a message to just the Agent and its Node. + + - Select a Node to send a message to the Node and all its Agents. + + - Select (All Nodes) to send a message to all the Nodes and all + their Agents. + +2. Click Send Message from the Server Toolstrip or the Network View Pane + context menu. + +3. In the Send Message dialog, enter the message text, topic and any + data items. + +4. Click Ok to confirm, or Cancel to cancel the operation. + +.. image:: _images/serverapp/image27.png + :width: 3.6113in + :height: 5.16667in + +Message sending is graphically depicted in the Network Graph View. +Messages are shown traveling from the source (in this case the Server) +to one or more destinations (in this case Node1 and all its Agents). + +.. image:: _images/serverapp/image28.png + :width: 6.5in + :height: 5.68056in + +The source entity is highlighted with a large rectangle and the +destination entity are highlighted with small rectangles. + +Server messages (generated using the Send Message command) are shown in +orange. + +Agent messages (generated by agent Behaviors) are shown in light blue. + +** +** + +**Sending Files to a Node** +=========================== + +The Send File command allows the user to send a file from the SAGE +server to one or more Nodes when the Server is active. + +To send a file: + +1. Select the Node(s) from the Server Toolstrip or the Network View + Pane. + + - Select a Node to send the file to just that Node. + + - Select (All Nodes) to send a file to all the Nodes. + +2. Click Send File from the Server Toolstrip or the Network View Pane + context menu. + +3. Navigate to the desired folder and select the file to send. + +4. Click Open to confirm, or Cancel to cancel the operation. + +A sub-folder with the same name as the Node will be created (if it does +not already exist) in the SAGE data directory on the targeted Node +machine where the sent files will be copied to. + +“\ *C:\\ProgramData\\Sage\\data\\NodeName”* + +**Viewing Agent State Spaces** +============================== + +Every SAGE agent has a State Space which includes the following +information: + +- Agent name + +- Node name + +- The “sageHome” directory + +- The “sageNodeHome” directory + +An active Agent can have additional named States which are created and +managed by one or more of its Behaviors. + +To view the State Space for one or more Agents: + +1. Select the Agent(s) from the Server Toolstrip or Network View Pane. + + - Select an Agent to view its State Space. + + - Select a Node to display the State Spaces of all Agents on the + Node. + + - Select (All Nodes) to display the State Spaces of all Agents on + all SAGE nodes. + +2. Click Show State Space from the Server Toolstrip or the Network View + Pane context menu. + + - If the State Space is already open, this will bring it to the + foreground. + +The Agent State Space below shows a number of additional states which +were created and are dynamically managed by the Agent’s Behavior. + +.. image:: _images/serverapp/image29.png + :width: 6.49049in + :height: 5.50077in + +To hide open Agent State Space(s), either click the State Space window’s +Close button or do the following: + +1. Select the Agent(s) from the Server Toolstrip or Network View Pane. + + - Select an Agent to hide its State Space. + + - Select a Node to hide the State Spaces of all Agents on the Node. + + - Select (All Nodes) to hide the State Spaces of all Agents on all + SAGE nodes in the foreground. + +2. Click Hide State Space from the Server Toolstrip or the Network View + Pane context menu. + +**The SAGE Robot Interface** +============================ + +The SAGE Robot Interface allows you to run Robot scripts and view the +results from within the SAGE Server App. + +Click the Robot Interface button on the Server Toolstrip to start a new +instance of the SAGE Robot Interface, as shown below. + +.. image:: _images/serverapp/image30.png + :width: 6.5in + :height: 7.69931in + +At the top of the window are controls to select and sequence the Robot +script files. + +Robot scripts are added, removed and sequenced using the buttons to the +right of the Robot scripts list. + +The Add and Remove operations are also available from the File menu. + +To run a Robot script: + +1. Open Robot Interface + +2. Click the Add button . + +3. Select the Robot file and click Open. + +4. Repeat steps 1 and 2 to add additional Robot scripts. + +5. Click the Start button to start the run. + +The Robot scripts will be run one at a time in the sequence specified. + +Clicking the Stop button will abort the run. + +When a Robot script successfully completes, the pathname of the +generated report file appears in the report list at the bottom of the +window. + +.. image:: _images/serverapp/image31.png + :width: 6.5in + :height: 7.69931in + +To view a report, select it from the report list and click the Report +button located in the bottom-right corner. You may also right-click the +report pathname and select View Report from the context menu. + +**The Log Viewer** +================== + +The display of Server-generated log events are handled by the Log +Viewer. + +The types of log events include exceptions, errors, warning, +informational messages, and behavior execution results. + +By default a single-line header is displayed showing the timestamp, +event type, and a brief description. + +.. image:: _images/serverapp/image32.png + :width: 6.5in + :height: 5.93681in + +Message and result events can be expanded to show additional +information. + +Only one log event can be expanded at a time. + +The Logger Toolstrip provides buttons for copying log events to the +Windows clipboard and for clearing the Log Viewer. These commands are +also available on the context menu displayed when right-clicking on a +log event. + +When the Server is stopped, currently displayed event logs remain. + +All events, including removed events, are saved to a log data file +located in *C:\\ProgramData\\SAGE\\logs*. + +**Loading and Saving an Agent Network** +======================================= + +Agent network configurations can be saved and loaded. The files are +saved as two JSON files with a common base filename and the extensions +“.sage” and “.sagenode”. + +- The Node Network JSON file has extension “.sagenode” and is used by + the SAGE Node Manager to start the Managed Nodes. + + - Node networks can be independently loaded and saved from the Node + Manager using the Load Managed Nodes and Save Managed Nodes + menu buttons, even when the Server is inactive. + +- The Agent Network JSON file has extension “.sage” is used by the SAGE + Server to load the Agents and their Behaviors on the connected Nodes. + + - This is the file that the user sees when loading or saving an + Agent Network from the App. It will always be accompanied by + the companion “.sagenode” file used by the Node Manager to + start the Nodes. + +**Saving an Agent Network** + +The current Agent network configuration can be saved (exported) when the +Server is active. + +To save an Agent network: + +1. Click the Save Network button on the Control Toolstrip. + +2. Navigate to the desired folder for saving the network configuration + files. + +3. Enter a filename for your Agent Network configuration (must have + extension “.sage”). + +4. Click the Save button. + +**Loading an Agent Network** + +A previously saved network configuration can be loaded (imported) when +the Server is inactive. + +To load an Agent network: + +1. Click the Load Network button on the Control Toolstrip. + +2. Navigate to the folder containing the previously saved network + configuration files and select the Agent Network file (with extension + “.sage”). + +3. Click the Open button. + +The SAGE Server will start and the Node Manager will attempt to start +any missing Nodes. The Server will then perform a validation check on +the JSON tree by ensuring that all Nodes referenced in the network exist +and that all Behaviors to be added to the Agents exists in the Behavior +repository. + +If there are any errors (e.g., missing Nodes or Behaviors), an “Agent +Network Load Errors” dialog window will appear listing the errors. + +The dialog window remains open while the user attempts to resolve the +issues. + +.. image:: _images/serverapp/image33.png + :width: 6.5in + :height: 5.67431in + +In the above example, two Nodes residing on the remote Host named +“surface-laptop” could not be started because the remote Host was +offline. The issue is resolved by bringing “surface-laptop” back online. + +Click the Retry button to retry loading the network configuration, or +click Cancel to abort the operation. + +If there are no more errors, the Server is able to create the Agents and +load their Behaviors so that the saved network is fully configured. + +.. image:: _images/serverapp/image34.png + :width: 6.5in + :height: 5.77917in + +.. |image1| image:: _images/serverapp/image6.png + :width: 6.5in + :height: 5.92569in +.. |image2| image:: _images/serverapp/image9.png + :width: 3.19792in + :height: 2.73701in +.. |image3| image:: _images/serverapp/image10.png + :width: 3.09375in + :height: 2.72168in +.. |image4| image:: _images/serverapp/image13.png + :width: 3.23891in + :height: 3.23194in +.. |image5| image:: _images/serverapp/image14.png + :width: 3.21875in + :height: 3.23274in +.. |image6| image:: _images/serverapp/image18.png + :width: 2.99283in + :height: 3.89583in +.. |image7| image:: _images/serverapp/image19.png + :width: 2.95833in + :height: 3.87056in diff --git a/docs/_build/html/_sources/sage_node.rst.txt b/docs/_build/html/_sources/sage_node.rst.txt new file mode 100644 index 0000000..b554b25 --- /dev/null +++ b/docs/_build/html/_sources/sage_node.rst.txt @@ -0,0 +1,54 @@ +SAGE Node +========================== + + +.. figure:: _images/Sage_Node.png + :align: center + + +SAGE Nodes are containers for your SAGE Agents. A single Node can manage hundreds of Agents. + + +Nodes connect directly to the SAGE Server and must be uniquely identifiable by name. Nodes are usually deployed on systems based on the locality of the automation. For example, in a SOA test automation scenario, SAGE Nodes would be deployed on the system under test (SUT). + +A SAGE Node fulfills a number of functions including: + +- Handling incoming requests from other Agents for message delivery, including file download and upload. +- Agent creation and deletion +- Agent Behavior management +- Agent activation and deactivation, . +- Scheduling the execution of Agent Behaviors. +- Communicating with the SAGE Sever to deliver requests to remote Agents. +- Reporting the results of Behavior execution back to the Server. +- Implementing synchronization between Agents. + + +.. _agent-label: + +SAGE Agent +++++++++++++++++++++++++++ +SAGE Agents are autonomous, active objects that execute your automation code (Behaviors). Agents exist within a SAGE Node instances. + +They contain a state space that consists of name-value tuples, providing Agents with the information they need to carry out their behaviors. + +Agent names only have to be unique within the Node that contains them. + +Agents in SAGE are constructed dynamically, at runtime, through requests from the SAGE Server or from other Agents. +This capability enables Agents to create and configure other Agents at runtime. + +SAGE Agent services include: + +- Create and destroy Agents +- Configure Agents +- Activate and Deactivate Agents +- Send messages to Agents +- Execute Behaviors + +Addressing an Agent in a SAGE runtime requires both the Node name as well as the Agent name. + +.. code-block:: python + + Create Agent TestNode TestAgent + Add Behavior TestNode TestAgent ExampleBehavior ExampleBehavior.jar + Activate Agent TestNode TestAgent + diff --git a/docs/_build/html/_sources/sage_robot_framework_keywords.rst.txt b/docs/_build/html/_sources/sage_robot_framework_keywords.rst.txt new file mode 100644 index 0000000..ecccc04 --- /dev/null +++ b/docs/_build/html/_sources/sage_robot_framework_keywords.rst.txt @@ -0,0 +1,10 @@ +SAGE Robot Framework Keywords +==================================================================== + +.. raw:: html + + + + + + diff --git a/docs/_build/html/_sources/sage_server.rst.txt b/docs/_build/html/_sources/sage_server.rst.txt new file mode 100644 index 0000000..22a805a --- /dev/null +++ b/docs/_build/html/_sources/sage_server.rst.txt @@ -0,0 +1,37 @@ +SAGE Server +========================== + +.. figure:: _images/Sage_Server.png + :align: center + + +The SAGE Server establishes and maintains a connection between SAGE Nodes, other SAGE Servers, and external controller systems connected through the SAGE Remote Interface. + +SAGE Server acts as a hub connecting local SAGE Nodes forming a cluster. It provides agents within this cluster with the following services: + +Communication + - Exchange messages with agents residing in Nodes in the local cluster or in remote clusters +Introspection + - Discover Nodes, Agents, and remote Servers +Agent Management + - Create and destroy Agents + - Add and remove Agent behaviors + - Activate and deactivate Agents +Runtime Control + - Retrieve Behavior execution results + - Synchronize execution of SAGE behaviors +Behavior Management + - Hosts the Behavior repository + - Synchronize the Behavior repository across clusters + - Manage Behavior delivery to Agents +Server Clusters + - SAGE supports a Fog Computing model where multiple SAGE Servers reside in different cloudlets connected over long haul networks. Agents residing within a cluster are tighly coupled so that they can perform collabrative tasks that require agents to synchronize thier actions at or near real-time. Agent interaction between clusters is assumed to be unreliable and, to varying degrees, latent. Agents could interact across clusters to report events, share state (e.g. ML models for distributed learning), or communicate new goals. + - In the example below, we depict two agent clusters performing a coordinated search operation where a group of unmanned aircraft systems (UAS) are canvassing a region searching for some target. The agents in this instance must coordinate their actions to optimize the search operation based on multiple criteria (e.g. area coverage, terrain features, energy consumption). The UASs then direct two unmanned ground systems (UGS) instrumented with proper sensors to move to areas where a match is found to verify the presence of the target. If a UGS confirms the find, it would direct a UGS specilized for object retrieval to traverse to that location and retrieve the object. The operation described above can be carried out in a completely autnomous fashion with operators in a remote location are simply observing the operation under way. + + + + +.. figure:: _images/SageCluster.png + :width: 650 px + :align: center + diff --git a/docs/_build/html/_sources/sending_messages_between_agents.rst.txt b/docs/_build/html/_sources/sending_messages_between_agents.rst.txt new file mode 100644 index 0000000..dedb808 --- /dev/null +++ b/docs/_build/html/_sources/sending_messages_between_agents.rst.txt @@ -0,0 +1,96 @@ +Sending Messages Between Agents +==================================================== + +SAGE Agents have the built-in ability to communicate across the network. + +This can be useful for: + - Controlling other agents dynamically. + - Sending pertinent information, such as files, across your agent network. + - Gathering information regarding your agent network. + +The Message class provides the necessary mechanism to specify a message recipient and the message content. + +- **m_targetNodeName** [string] + This is the name of the SAGE Node that is the recipient of this message. If left empty, the message is sent to all the Nodes in the SAGE network. + +- **m_targetAgentName** [string] + This is the name of the SAGE Agent that is the recipient of this message. If left empty, the message is sent to all the Agents in the specified SAGE Node. + +- **m_topic** [string] + If specified, a topic name acts to direct a message to only those Behaviors that have that topic included in their topics list. This provides a filtering mechanism so that messages are only sent to those Behaviors interested in them. + +- **m_message** [string] + This is an arbitrary, application defined string that specifies what the message is. + +- **m_data** [string vector] + This string vector allows the message sender to include an arbitrary number of data items with the message. The content of that data is application defined. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + class Message + { + public: + std::string m_targetNodeName; + std::string m_targetAgentName; + std::string m_topic; + std::string m_message; + std::vector m_data; + } + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public class Message + { + public String m_targetNodeName; + public String m_targetAgentName; + public String m_topic; + public String m_message; + public ArrayList m_data = new ArrayList(); + } + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + class Message(object): + def __init__(self): + self.m_targetNodeName = str() + self.m_targetAgentName = str() + self.m_topic = str() + self.m_message = str() + self.m_data = [] + + +Invoke the :mod:`sendMessage` method using your Message as the argument to communicate with other Agents in the SAGE Agent network. + + +.. code-block:: Java + + Message myMessage = new Message(); + + myMessage.m_message = "Hello"; + myMessage.m_targetNodeName = "nodeName1"; + myMessage.m_targetAgentName = "newAgentName1"; + sendMessage(myMessage); + +As a result, the recipient agent (newAgentName1) will receive a message containing the message content "Hello". + + diff --git a/docs/_build/html/_sources/starting_a_server_instance.rst.txt b/docs/_build/html/_sources/starting_a_server_instance.rst.txt new file mode 100644 index 0000000..8f44f1d --- /dev/null +++ b/docs/_build/html/_sources/starting_a_server_instance.rst.txt @@ -0,0 +1,30 @@ +Starting a Server Instance +===================================================== + +**Initialize Server** + +On a :mod:`Windows` command prompt enter the following command: + + .. code-block:: bat + + SageServerConsole_x64.exe {port_number} + +On a :mod:`Linux` terminal enter the following command: + + .. code-block:: bat + + SageServerConsole {port_number} + + +To verify a running SAGE Server instance, check the prompt window and confirm that the following text is displayed + ``SAGE server started listening on port: {port_number}``. + + +This can also be accomplished using the SAGE App: + + 1) In the SAGE App, configure your :ref:`serverAppSettings-label` by clicking the gear icon :mod:`Settings` button. + 2) Enter a port number in the Server Port dialog box and click the :mod:`Ok` button. + 3) Click the green :mod:`Start` button to initialize the Server. + + +Note that there is no default port number for SAGE. It is recommended to avoid using dedicated port numbers, such as 21 (FTP), 22 (SSH), and 80 (HTTP). For a list of unassigned port numbers visit `Internet Assigned Numbers Authority (IANA) `_. diff --git a/docs/_build/html/_sources/using_supplemental_files_in_your_automation.rst.txt b/docs/_build/html/_sources/using_supplemental_files_in_your_automation.rst.txt new file mode 100644 index 0000000..80f4963 --- /dev/null +++ b/docs/_build/html/_sources/using_supplemental_files_in_your_automation.rst.txt @@ -0,0 +1,28 @@ +Using Supplemental Files in Your Automation +================================================================================================ + +There are many cases in which your automation test may require files other than Behaviors, such as images, text files, executables, or other libraries. + +These files can be used to support your automation scripts at the **Node** level. + +Supplemental files should be manually placed in the following directory on the targeted **Node machine**: + ++-------------+-----------------------------+ +| | Data Path | ++=============+=============================+ +| **Windows** | C:\\ProgramData\\Sage\\data | ++-------------+-----------------------------+ +| **Linux** | /etc/Sage/data | ++-------------+-----------------------------+ + + +**Update SAGE_CLASSPATH environment variable if needed** + +SAGE runtime uses the :mod:`SAGE_CLASSPATH` environment variable. + +If your Behavior needs to load other classes found within a separate library, such as a JAR file, be sure to append that file to the :mod:`SAGE_CLASSPATH` environment variable. + + 1) On the targeted Node machine, copy the library into the SAGE data directory. + 2) Add your library to the :mod:`SAGE_CLASSPATH` environment variable, e.g., *C:\\ProgramData\\Sage\\data\\*. + + diff --git a/docs/_build/html/_sources/writing_a_sage_behavior.rst.txt b/docs/_build/html/_sources/writing_a_sage_behavior.rst.txt new file mode 100644 index 0000000..995ef54 --- /dev/null +++ b/docs/_build/html/_sources/writing_a_sage_behavior.rst.txt @@ -0,0 +1,754 @@ +Writing a SAGE Behavior +============================================ + +SAGE Behaviors are classes that are be developed, outside of the main SAGE codebase, and ran by SAGE Agents. An example Behavior might be a Python module that when invoked uses a Java package to test an external application and make the test results available to the SAGE Server. + +Behaviors can be written so that agents can perform either **reactively in response to an incoming message**, or **proactively on a continuous or one time basis.** + +Behavior objects must contain four methods that constitute their execution repertoire: + +- ``setUp`` This method is called when a Behavior is instantiated and is expected to perform initialization activities. Behaviors are instantiated when an Agent becomes active, or when a new Behavior is added to an active Agent. +- ``action`` This method implements the proactive execution of a Behavior based on the execution mode specified. + - OneShot execution activates the ``action`` method once when the Agent is activated. + - Periodic execution activates the ``action`` method continuously. + - TimedPeriodic execution activates the ``action`` method every *n* milliseconds. + - OnMessage activates the ``action`` method upon the receipt of a specific message. +- ``message`` This method is called when an Agent receives a message. Behaviors can specify a topic filter consisting of a list of topics that the Behavior is interested in. Incoming messages that do not specify one of those topics in the topic filter are not propagated to the Behavior. +- ``tearDown`` This method is called on each Behavior when an Agent is deactivated. It is expected to perform any de-initialization activities necessary to bring the system to a known state. + +Each method can populate a Result object that includes the result of the execution as well as a log of the activities performed during the execution. Result objects that specify an execution result other than ``NotSet`` (see below) are passed back to the Server. + +Behaviors are run by (within) a SAGE Node process. When a Behavior is added to an :ref:`agent-label`, its executable module is sent to the Node containing the Agent so that it can be scheduled for execution by that Node. + + + + +Inheritance from the base class +++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +Behaviors can be written in C++, Java, or Python. In each language a SAGE Behavior is a class and is required to conform to a specific interface. This includes inheriting from a base class and using specific objects provided by the SAGE Framework. To develop C++ Behaviors you will need to install the SAGE SDK. Behaviors developed in Java or Python do not require the SAGE SDK. + + +Every C++ Behavior class, in this example named "ExampleCppBehavior", is a subclass (child) of NativePluginInterface. The NativePluginInterface header file is available in the SAGE SDK. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + class ExampleCppBehavior : public NativePluginInterface + + +In Java every Behavior is a subclass of SageBehavior. The Java SageBehavior class code is in the SageJavaBehaviorInterface.jar file distributed with the SAGE Node installer. The Java source files are distributed in the SAGE SDK. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public class ExampleJavaBehavior extends SageBehavior + + +In Python every Behavior is a subclass of SageBehavior. The Python SageBehavior code is in the file SagePythonBehaviorInterface-1.0-py2.7.egg which is distributed with the SAGE Node and SAGE Server installers. The code itself is distributed in the SAGE SDK. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + class ExamplePythonBehavior(SageBehavior.SageBehavior): + + +Result object +++++++++++++++++++++++++++++++++++++++++++++++++++++ + +A Result object provides a reporting mechanism back to the Server to indicate the results of the execution of a Behavior's :mod:`setup()`, :mod:`action()`, :mod:`message()`, or :mod:`teardown()` methods. + +A Result object contains the following three members that should be assigned appropriate values by the Behavior developer: + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + std::vector m_logMessages; + std::string m_exception; + ExecutionResultType m_executionResult; + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public ArrayList m_logMessages = new ArrayList(); + public String m_exception = ""; + public ExecutionResultType m_executionResult = ExecutionResultType.CompletionSuccess; + + .. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + self.m_logMessages = [] + self.m_exception = "" + self.m_executionResult = ExecutionResultType.CompletionSuccess + +- **m_logMessages** is a vector of strings and is intended to provide a log of events that occurred during the execution of a Behavior. + +- **m_exception** if the execution of code in the method generates an exception, the m_exception string should contain text describing the cause of the exception. + +- **m_executionResult** this member consists of an enumeration of type ExecutionResultType. It can have one of three values: + - ``CompletionSuccess`` - the method completed execution successfully + - ``CompletionFailure`` - the method completed execution but failed + - ``ExceptionThrown`` - code in the method caused an exception to be thrown. It is highly recommended that Behavior developers execute any code that can potentially generate exceptions within a try - catch statement. + - ``NotSet`` - the method has not yet assigned m_executionResult a value. + + +Behavior constructor +++++++++++++++++++++++++++++++++++++++++++++ + +It is a requirement for SAGE Behaviors that their **constructors only set member variables**. There should be no significant code executed in a Behavior constructor. This is because the SAGE Framework may instantiate and destroy Behaviors when doing inquiry functionality. Any startup related code should be put in the :mod:`setUp()` method. + +Behaviors in all three languages have the same members declared in the base class. + +There are six members: + +- **m_name** [a string] + This is the Behavior's name. + Other parts of the SAGE system depend on this name (and the Behavior's filename) to find and execute the Behavior. +- **m_description** [a string] + A description of the Behavior. +- **m_executionType** + Set to ``OneShot``, ``Cyclical``, ``TimedCyclical``, ``OnMessage``, or ``NoExecution``. + These values all pertain to when the Behavior's action() method will be invoked. + + - ``OneShot`` action() is called once when the Agent is activated. + - ``Cyclical`` action() is called continuously after the Agent is activated. + - ``TimedCyclical`` action() is called continuously every m_period milliseconds after the Agent is activated. + - ``OnMessage`` action() is called upon the receipt of a message that matches m_triggerMessage. Do not confuse this with the Behavior's message() method. + - ``NoExecution`` action() is not called. The Behavior is still created, setUp() is invoked, and the Behavior can be used via the message() method. +- **m_triggerMessage** [a string] + If the Behavior's **m_executionType** is ``OnMessage`` then action() will be invoked when a message is sent from elsewhere in the SAGE system that matches the string **m_triggerMessage**. +- **m_period** [time in in milliseconds] + If the **m_executionType** is ``TimedCyclical`` then the action() method will be called every **m_period** milliseconds. +- **m_delay** [time in in milliseconds] + This is the initial amount of time the Behavior's Agent will wait before calling the Behavior's action(). + A Behavior is instantiated when its Agent is activated or when a Behavior is added to an active Agent. At that time the Behavior's setUp() method is also called. If the Behavior has defined an **m_executionType** of ``OneShot``, ``Cyclical``, or ``TimedCyclical`` then the action() will first be called after **m_delay** milliseconds have passed. + + +In C++, SAGE enforces this requirement by requiring that a Behavior's constructor be created using a macro **SAGE_BEHAVIOR** (defined in NativePluginInterface.h). Use of this macro also allows a SAGE Server running on Windows to inspect an .so file created under Linux. + +.. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + SAGE_BEHAVIOR(CLASS_NAME, BEHAVIOR_NAME, BEHAVIOR_DESCRIPTION, EXECUTION_TYPE, TRIGGER_MESSAGE, PERIOD, DELAY) + +The first parameter should be the name of the class. The remaining map to each of the six members. + +In Java and Python, the members should be set in the constructor. + +.. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public ExampleJavaBehavior() + { + m_name = "SimpleExample"; + m_description = "Simple description"; + m_executionType = ExecutionType.OneShot; + m_triggerMessage = ""; + m_period = 0; + m_delay = 0; + } + +.. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def __init__(self): + super(ExamplePythonBehavior, self).__init__() + self.m_name = "SimpleExample" + self.m_description = "Simple description" + self.m_executionType = ExecutionType.ExecutionType.OneShot + self.m_triggerMessage = "" + self.m_period = 0 + self.m_delay = 0 + + +Behavior setUp ++++++++++++++++++++++++++ + +This method is called when a Behavior is instantiated and is expected to perform initialization activities. Behaviors are instantiated when an Agent becomes active, or when a new Behavior is added to an active Agent. + +- **result** [Result object] + Results of this method's execution should be reported using Result object. Result objects contain m_logMessages, m_exception, or m_executionResult. + + +It returns true or false; false indicates that there is a SAGE Behavior internal error meaning this Behavior should not be run again. + +.. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool ExampleCppBehavior::setUp(sageframework::Result& result) + { + result.m_logMessages.push_back("This is log message string3."); + result.m_exception = "Nothing exceptional here."; + result.m_executionResult = sageframework::ExecutionResultType::NotSet; + return true; + } + +.. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean setUp(Result result) + { + result.m_logMessages.add("This is log message string3."); + result.m_exception = "Nothing exceptional here."; + result.m_executionResult = ExecutionResultType.NotSet; + return true; + } + +.. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def setUp(self, result): + result.m_logMessages.append("This is log message string3.") + result.m_exception = "Nothing exceptional here." + result.m_executionResult = ExecutionResultType.ExecutionResultType.NotSet + return True + +Behavior action +++++++++++++++++++++++++++++++++++++++ + +This method is called based on the execution type (m_executionType) specified in the Behavior constructor. Execution types include, :mod:`OneShot`, :mod:`Cyclical`, :mod:`TimedCyclical`, :mod:`OnMessage`, or :mod:`NoExecution`. This is method is a proactive response. + +- **result** [Result object] + Results of this method's execution should be reported using Result object. Result objects contain m_logMessages, m_exception, or m_executionResult. + +It returns true or false; false indicates that there is a SAGE Behavior internal error meaning this Behavior should not be run again. + +.. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool ExampleCppBehavior::action(sageframework::Result& result) + { + result.m_logMessages.push_back("This is log message string."); + result.m_exception = "Nothing exceptional here."; + result.m_executionResult = sageframework::ExecutionResultType::CompletionSuccess; + return true; + } + +.. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean action(Result result) + { + result.m_logMessages.add("This is log message string."); + result.m_exception = "Nothing exceptional here."; + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + +.. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def action(self, result): + result.m_logMessages.append("This is log message string.") + result.m_exception = "Nothing exceptional here." + result.m_executionResult = ExecutionResultType.ExecutionResultType.CompletionSuccess + return True + + +Behavior message +++++++++++++++++++++++++++++++++++++++ + +This method is called when an Agent receives a message. This is method is a reactive response. Elsewhere is the SAGE system Behaviors are specified to have a topic filter consisting of a list of topics that the Behavior is interested in. + +Incoming messages that do not specify one of those topics in the topic filter are not propagated to the Behavior. + +- **Message** [Message object] + Provides the necessary mechanism to retrieve the message content sent to the message recipient. Messages may contain m_targetNodeName, m_targetAgentName, m_topic, m_message, and m_data. +- **result** [Result object] + Results of this method's execution should be reported using Result object. Result objects contain m_logMessages, m_exception, or m_executionResult. + + +It returns true or false; false indicates that there is a SAGE Behavior internal error meaning this Behavior should not be run again. + +.. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool ExampleCppBehavior::message(const sageframework::Message& message, sageframework::Result& result) + { + std::cout << "Got message " << message.m_message << " on topic " << message.m_topic << std::endl; + std::cout << "len of m_data is " << message.m_data.size() << std::endl; + result.m_logMessages.push_back("This is log message from message string1."); + result.m_exception = "Nothing exceptional here."; + result.m_executionResult = sageframework::ExecutionResultType::CompletionSuccess; + return true; + } + +.. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean message(Message message, Result result) + { + System.out.println("Got message " + message.m_message + " on topic " + message.m_topic); + System.out.println("length of m_data is", message.m_data.size()); + result.m_logMessages.add("This is log message from message string1."); + result.m_exception = "Nothing exceptional here."; + result.m_executionResult = ExecutionResultType.CompletionSuccess; + return true; + } + +.. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def message(self, message, result): + print("Got message ", message.m_message, " on topic ", message.m_topic) + print("length of m_data is", len(message.m_data) ) + result.m_logMessages.append("This is log message from message string1.") + result.m_exception = "Nothing exceptional here." + result.m_executionResult = ExecutionResultType.ExecutionResultType.CompletionSuccess + return True + + +Behavior tearDown ++++++++++++++++++++++++++++++++++++ + +This method is called when the Agent is deactivated. It should perform any clean-up and shutdown activities. + +- **result** [Result object] + Results of this method's execution should be reported using Result object. Result objects contain m_logMessages, m_exception, or m_executionResult. + +It returns true or false; false indicates that there is a SAGE Behavior internal error meaning this Behavior should not be run again. + +.. container:: toggle + + .. container:: header + + C++ + + .. code-block:: cpp + + bool ExampleCppBehavior::tearDown(sageframework::Result& result) + { + result.m_logMessages.push_back("This is log message string3."); + result.m_exception = "Nothing exceptional here."; + result.m_executionResult = sageframework::ExecutionResultType::NotSet; + return true; + } + +.. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + public boolean tearDown(Result result) + { + result.m_logMessages.add("This is log message string3."); + result.m_exception = "Nothing exceptional here."; + result.m_executionResult = ExecutionResultType.NotSet; + return true; + } + +.. container:: toggle + + .. container:: header + + Python + + .. code-block:: python + + def tearDown(self, result): + result.m_logMessages.append("This is log message string3.") + result.m_exception = "Nothing exceptional here." + result.m_executionResult = ExecutionResultType.ExecutionResultType.NotSet + return True + + +C++ header file +++++++++++++++++++++++++++++++++++++++++ + +C++ requires a header file. In addition to providing declarations of the required four methods, the header file must include a line required by the Boost Dll library that SAGE uses to manage dynamic load libraries. + +The static create() method is a factory method that creates instances of the behavior class. + +The BOOST_DLL_ALIAS statement exports that symbol so that SAGE can find it in the dynamic load library and invoke it. + +The use of a factory method to load the behavior class means that each C++ dll/so can only contain one behavior class. While this is a restriction, its likely a good practice to follow in general. + +Here is a example header file called ExampleCppBehavior.h: + +.. code-block:: cpp + + #pragma once + + #include "NativePluginInterface.h" + + // This class will be compiled into ExampleCppBehavior.dll under Windows + // or ExampleCppBehavior.so under Linux. + // + class ExampleCppBehavior : public NativePluginInterface + { + public: + ExampleCppBehavior(); + bool setUp(sageframework::Result& result); + bool action(sageframework::Result& result); + bool message(const sageframework::Message& message, sageframework::Result& result); + bool tearDown(sageframework::Result& result); + + // Factory method + static boost::shared_ptr create() + { + return boost::shared_ptr(new ExampleCppBehavior()); + } + }; + + BOOST_DLL_ALIAS + ( + ExampleCppBehavior::create, // <-- this function is exported with... + create_plugin // <-- ...this alias name + ) + + + +Example Behavior file ++++++++++++++++++++++++++++++++++++ + +This is an example Behavior in its entirety. Other parts of the SAGE system would refer to this as the Behavior named ExampleBehavior. This Behavior does not do anything useful, but it defines each of the four required methods, will print out when each is called, and fills in the result parameter. + +.. container:: padding + + .. container:: toggle + + .. container:: header + + C++ + + .. code-block:: c++ + + // ------------------------------- Header file ------------------------------- + #pragma once + + #include "NativePluginInterface.h" + + // This class is exported from the ExampleCppBehavior.dll + class ExampleCppBehavior : public NativePluginInterface + { + public: + ExampleCppBehavior(); + virtual bool setUp(sageframework::Result& result); + virtual bool action(sageframework::Result& result); + virtual bool message(const sageframework::Message& message, sageframework::Result& result); + bool tearDown(sageframework::Result& result); + + // Factory method + static boost::shared_ptr create() + { + return boost::shared_ptr(new ExampleCppBehavior()); + } + }; + + BOOST_DLL_ALIAS + ( + ExampleCppBehavior::create, // <-- this function is exported with... + create_plugin // <-- ...this alias name + ) + + // ---------------------------- cpp behavior file ------------------------------ + // ExampleCppBehavior.cpp : Defines the exported functions for the DLL. + // + + #include "stdafx.h" + #include "Common.h" + #include "Message.h" + #include "Result.h" + #include "ExampleCppBehavior.h" + + SAGE_BEHAVIOR(ExampleCppBehavior, SimpleExample, does something cool, sageframework::ExecutionType::OneShot, "", 0, 0) + + bool ExampleCppBehavior::setUp(sageframework::Result& result) + { + std::cout << "Setting up behavior" << std::endl; + result.m_executionResult = sageframework::ExecutionResultType::CompletionSuccess; + return true; + } + + bool ExampleCppBehavior::action(sageframework::Result& result) + { + std::cout << "Hello World from Action" << std::endl; + result.m_logMessages.push_back("This is log message string1."); + result.m_logMessages.push_back("This is log message string2."); + result.m_logMessages.push_back("This is log message string3."); + result.m_exception = "Nothing exceptional here."; + result.m_executionResult = sageframework::ExecutionResultType::CompletionSuccess; + + return true; + } + + bool ExampleCppBehavior::message(const sageframework::Message& message, sageframework::Result& result) + { + std::cout << "Got message " << message.m_message << " on topic " << message.m_topic << std::endl; + std::cout << "len of m_data is " << message.m_data.size() << std::endl; + + for (int i=0; i < message.m_data.size(); i++) + { + std::cout << "Data[" << i << "] = " << message.m_data[i] << std::endl; + } + + result.m_logMessages.push_back("This is log message from message string1."); + result.m_exception = "Nothing exceptional here."; + result.m_executionResult = sageframework::ExecutionResultType::CompletionSuccess; + + return true; + } + + bool ExampleCppBehavior::tearDown(sageframework::Result& result) + { + std::cout << "Tearing down behavior " << m_name << std::endl; + result.m_executionResult = sageframework::ExecutionResultType::CompletionSuccess; + return true; + } + + .. container:: toggle + + .. container:: header + + Java + + .. code-block:: java + + /* Example SAGE Behavior in Java. + Shows the four methods that have to be defined: + setUp, action, message, tearDown + + Use the following command line to build: + javac -cp "%SAGE_SERVER_HOME%"\SageJavaBehaviorInterface.jar ExampleJavaBehavior.java + + Create jar file + jar cf ExampleJavaBehavior.jar ExampleJavaBehavior.class + */ + + + import nrl.sage.BehaviorInterface.*; + + + public class ExampleJavaBehavior extends SageBehavior + { + public ExampleJavaBehavior() + { + m_name = "SimpleExample"; + m_description = "Simple behavior that prints a lot"; + m_executionType = ExecutionType.OneShot; + m_delay = 15000; + } + + public boolean setUp(Result result) + { + /* The class needs a setUp. Return True or False */ + System.console().printf("Setting up behavior %s\n", m_name); + result.m_executionResult = ExecutionResultType.CompletionSuccess; + + return true; + } + + public boolean action(Result result) + { + /* The class needs an action fill in result. Return True or False */ + System.out.println("Hello World from Action"); + result.m_logMessages.add("This is log message string1."); + result.m_logMessages.add("This is log message string2."); + result.m_logMessages.add("This is log message string3."); + result.m_exception = "Nothing exceptional here."; + result.m_executionResult = ExecutionResultType.CompletionSuccess; + + return true; + } + + public boolean message(Message message, Result result) + { + /* The class needs a message message method. It is passed in a message object. Return True or False */ + System.out.println("Got message " + message.m_message + " on topic " + message.m_topic); + System.out.println("length of m_data is", message.m_data.size()); + for (int i=0; i= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + 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); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/docs/_build/html/_static/ajax-loader.gif b/docs/_build/html/_static/ajax-loader.gif new file mode 100644 index 0000000..61faf8c Binary files /dev/null and b/docs/_build/html/_static/ajax-loader.gif differ diff --git a/docs/_build/html/_static/basic.css b/docs/_build/html/_static/basic.css new file mode 100644 index 0000000..0807176 --- /dev/null +++ b/docs/_build/html/_static/basic.css @@ -0,0 +1,676 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2019 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%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +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 form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +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%; + margin-left: auto; + margin-right: auto; +} + +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 ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +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; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +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, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.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.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +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.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; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist td { + vertical-align: top; +} + + +/* -- 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, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.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 */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +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; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + 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; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- 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/docs/_build/html/_static/comment-bright.png b/docs/_build/html/_static/comment-bright.png new file mode 100644 index 0000000..15e27ed Binary files /dev/null and b/docs/_build/html/_static/comment-bright.png differ diff --git a/docs/_build/html/_static/comment-close.png b/docs/_build/html/_static/comment-close.png new file mode 100644 index 0000000..4d91bcf Binary files /dev/null and b/docs/_build/html/_static/comment-close.png differ diff --git a/docs/_build/html/_static/comment.png b/docs/_build/html/_static/comment.png new file mode 100644 index 0000000..dfbc0cb Binary files /dev/null and b/docs/_build/html/_static/comment.png differ diff --git a/docs/_build/html/_static/css/badge_only.css b/docs/_build/html/_static/css/badge_only.css new file mode 100644 index 0000000..3c33cef --- /dev/null +++ b/docs/_build/html/_static/css/badge_only.css @@ -0,0 +1 @@ +.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../fonts/fontawesome-webfont.eot");src:url("../fonts/fontawesome-webfont.eot?#iefix") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff") format("woff"),url("../fonts/fontawesome-webfont.ttf") format("truetype"),url("../fonts/fontawesome-webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} diff --git a/docs/_build/html/_static/css/custom.css b/docs/_build/html/_static/css/custom.css new file mode 100644 index 0000000..90d697d --- /dev/null +++ b/docs/_build/html/_static/css/custom.css @@ -0,0 +1,766 @@ +@import url("default.css"); /* make sure to sync this with the base theme's css filename */ + +/*ensure font is consistent across html*/ +html, body, pre, h1, h2, .rst-content .toctree-wrapper p.caption, table.docutils, h3, h4, h5, h6, legend{ + font-family: "Roboto", sans-serif; +} +p{ + color: rgba(0,0,0,0.71); + font-size: 16.8px; + line-height: 1.6; +} +body{ + line-height: 1.5; +} + +div.center.container { + text-align: center; +} + +/*code blocks */ +div[class^="highlight"] pre{ + font-family: 'Inconsolata', Monaco, Consolas, 'Andale Mono', monospace; + font-size: 1rem; + direction: ltr; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + line-height: 1.4; + -moz-tab-size: 4; + background: #f5f2f0; + margin: .5em 0; + overflow: auto; + padding: 5px 5px 5px 17px; +} +.codeblock div[class^="highlight"], pre.literal-block div[class^="highlight"], .rst-content .literal-block div[class^="highlight"], div[class^="highlight"]{ + background: #f5f2f0; +} +.codeblock, pre.literal-block, .rst-content .literal-block, .rst-content pre.literal-block, div[class^="highlight"] { + margin: 12px 0 24px 0; +} + + +/*Add background outside of content width */ +.wy-nav-content-wrap{ + background-color: #3c6fbd; +} + +/* Search bar exterior */ +.wy-side-nav-search{ + padding: 5px; +} +/* Search bar text area in nav*/ +.wy-side-nav-search input[type="text"] { + margin-top:15px; + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); + width: 95%; + -webkit-transition: width 0.4s ease-in-out; + transition: width 0.4s ease-in-out; + border-color: white; + padding: .9rem; + border-radius: 2px; +} +.wy-side-nav-search input[type="text"]:focus { + width: 100%; +} + +/* Edit upper left corner where search bar in contained */ +.wy-side-nav-search { + background: white; +} +/* Edit side bar */ +.wy-nav-side { + background: white; /*#141414;*/ + background-position: bottom left; + background-repeat: no-repeat; + background-attachment: fixed; + box-shadow: 0 4px 7px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); +} + +/* version number text from search area in upper-left corner*/ +.wy-side-nav-search > div.version { + margin-top:-2.27em; + margin-bottom:1em; + margin-left:-14.6em; + color: #141414; + display:none; +} + +.icon.icon-home { + font-size: 0px; + disply:none; +} + +/* Links */ +a { + color: #039be5; +} + +/* add padding & color to each item in Contents menu */ +.wy-menu-vertical a{ + padding: 1em 1.818em; + color:#141414; + font-size:13px; + +} +.wy-menu-vertical li.toctree-l2 a, .wy-menu-vertical li.toctree-l2.current > a{ + padding: 1.1em 3.027em; +} +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a{ + padding: 1.1em 4.045em; + +} + +/* Contents menu item currently clicked in depth level 1 */ +.wy-menu-vertical li.current > a, .wy-menu-vertical li.current a { + color: #404040; + padding-top: 1.1em; + padding-bottom: 1.1em; + font-weight: normal; + background-color: #eeeeee ; + border-bottom: none; + border-top: none; + border-right: none; +} + + +/* Contents menu item currently clicked in depth level 2*/ +.wy-menu-vertical li.toctree-l1.current ul li.toctree-l2.current a.reference.internal{ + padding-top: 1.1em; + padding-bottom: 1.1em; + font-weight: normal; + background-color: #c9c9c9 ; + border-bottom: none; + border-top: none; + border-right: none; +} + +/* Contents menu items not clicked in depth level 2*/ +.wy-menu-vertical li.toctree-l1.current ul li.toctree-l2 a.reference.internal{ + padding-top: 1.1em; + padding-bottom: 1.1em; + font-weight: normal; + background-color: white ; + border-bottom: none; + border-top: none; + border-right: none; +} +/* Contents menu item currently clicked in depth level 3*/ +.wy-menu-vertical li.toctree-l2.current ul li.toctree-l3.current a.reference.internal{ + color: white; + padding-top: 1.1em; + padding-bottom: 1.1em; + font-weight: normal; + background-color: #3c6fbd ; + border-bottom: none; + border-top: none; + border-right: none; +} + +/* Contents menu items not clicked in depth level 3*/ +.wy-menu-vertical li.toctree-l2.current ul li.toctree-l3 a.reference.internal{ + padding-top: 1.1em; + padding-bottom: 1.1em; + font-weight: normal; + background-color: white ; + border-bottom: none; + border-top: none; + border-right: none; +} + +/* Contents menu hover for current and not current */ +.wy-menu-vertical li.on a:hover, .wy-menu-vertical li.current > a:hover, .wy-menu-vertical a:hover,.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover,.wy-menu-vertical li.toctree-l2.current > a:hover, .wy-menu-vertical li.toctree-l2 a:hover, .wy-menu-vertical li.toctree-l2.current ul li.toctree-l3 a.reference.internal:hover, .wy-menu-vertical li.toctree-l1.current ul li.toctree-l2.current a.reference.internal:hover, .wy-menu-vertical li.toctree-l1.current ul li.toctree-l2 a.reference.internal:hover, .wy-menu-vertical li.toctree-l2.current ul li.toctree-l3.current a.reference.internal:hover { + background-color: #eeeeee ; + -webkit-transition: background 0.15s linear; + -moz-transition: background 0.15s linear; + -ms-transition: background 0.15s linear; + -o-transition: background 0.15s linear; + transition: background 0.15s linear; +} + +/* Contents menu on-click for current and not current */ +.wy-menu-vertical a.reference.internal:active, .wy-menu-vertical a.current.reference.internal:active, .wy-menu-vertical li.toctree-l2.current > a:active, .wy-menu-vertical li.current a:active, .wy-menu-vertical li.on a:active, .wy-menu-vertical li.current > a:active, .wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:active, .wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:active, .wy-menu-vertical li.toctree-l1.current ul li.toctree-l2 a.reference.internal:active, .wy-menu-vertical li.toctree-l1.current ul li.toctree-l2.current a.reference.internal:active, .wy-menu-vertical li.toctree-l1.current ul li.toctree-l2 a.reference.internal:active, .wy-menu-vertical li.toctree-l1.current ul li.toctree-l2 a.reference.internal:active { + background-color: black; + color:white; + -webkit-transition: background 0.12s linear; + -moz-transition: background 0.12s linear; + -ms-transition: background 0.12s linear; + -o-transition: background 0.12s linear; + transition: background 0.12s linear; + padding-top: 1.1em; + padding-bottom: 1.1em; +} + +/*menu items */ +.wy-menu-vertical { + padding-left: .25rem; +} +.wy-menu-vertical span.caption-text{ /* caption titles for menu items */ + font-weight:bold; + color:black; + font-size:13px; + text-transform: capitalize; +} + + +/* Hide view source */ +.wy-breadcrumbs li { + font-size: 0px; + display: none; +} + +/* Hide footer text contaning sphinx generation */ +footer { + font-size: 0px; +} +footer p{ + color: #9e9e9e ; + font-size: .9rem; + font-weight:lighter; +} + +.rst-footer-buttons { /* Ensure footer button texts stays readable*/ + font-size: medium; +} +/* index page section */ +#sage-framework{ + text-align:center; +} +#sage-framework h2{ + font-size:300%; +} +#getting-started, #getting-started ul li.toctree-l1{ /* remove bullets */ + list-style: none; + font-size:0px; + display: none; +} +#developer-s-guide, #developer-s-guide ul li.toctree-l1{ + list-style: none; + font-size:0px; + display: none; +} +#soa-test-support, #soa-test-support ul li.toctree-l1{ + list-style: none; + font-size:0px; + display: none; +} + +/* Download button */ +.xref.download.docutils.literal { + color: #26a69a; + background: white; + position: relative; + cursor: pointer; + display: block; + overflow: hidden; + vertical-align: middle; + -moz-user-select: none; + z-index: 1; + will-change: opacity, transform; + transition: all .3s ease-out; + padding: .9rem; + border-radius: 2px; + text-align: right; + letter-spacing: .5px; + border: none; + padding: .6rem 1.75rem; + /*text-transform: uppercase;*/ + font-family: "Roboto", sans-serif; + /*box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); + font-size:100%;*/ +} +.xref.download.docutils.literal:hover { /* Download button hover*/ + color: #00bfa5; + background: white; + position: relative; + cursor: pointer; + display: block; + overflow: hidden; + vertical-align: middle; + -moz-user-select: none; + z-index: 1; + will-change: opacity, transform; + transition: all .3s ease-out; + padding: .9rem; + border-radius: 2px; + text-align: right; + letter-spacing: .5px; + border: none; + padding: .6rem 1.75rem; + /* text-transform: uppercase;*/ + font-family: "Roboto", sans-serif; + /*box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); + font-size: .9rem; + font-size:100%;*/ +} +.xref.download.docutils.literal:active { + color: #80cbc4; + background: white ; + -webkit-transition: background 0.2s linear; + -moz-transition: background 0.2s linear; + -ms-transition: background 0.2s linear; + -o-transition: background 0.2s linear; + transition: background 0.2s linear; + /*font-size:100%;*/ +} + +/* download icon button */ +.rst-content code.download span:first-child::before { + display: inline-block; + width: 1.2em; + height: 1.2em; + content: ""; + background: url(ic_get_app_teal_18dp_2x.png) no-repeat 0 0; + background-size: 110%; + margin-right: 8px; + margin-bottom: -.2em; + margin-left: -.3em; +} + + +/* Download tables */ +.wy-table-odd td, .wy-table-striped tr:nth-child(2n-1) td, .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{ + background-color: white; +} +.wy-table-responsive{ + /*display: inline-block; + padding-right: 22px;*/ +} + +th.head{ /* Table headers */ + text-align: center; +} +tr { + /*text-align: center;*/ +} +.wy-table-bordered-all td, .rst-content table.docutils td { + border-bottom: 1px solid #d0d0d0; + border-left: .01px dotted transparent; + border-right: .01px dotted transparent; +} +.wy-table thead th, .rst-content table.docutils thead th, .rst-content table.field-list thead th { + font-weight: bold; + border-bottom: solid 1px #e1e4e5; + border-left: 1px solid transparent; + border-right: 1px solid transparent; + border-top: 1px solid transparent; +} +.rst-content table.docutils { + border: none; +} + + +/* Content area*/ +.wy-nav-content { + max-width: none; + background-color: white; + padding: 0 5.336em 1.618em 5.336em; +} + +/* Headers */ +h1 { + display:none; + font-size: 0px; + padding-bottom: 1.2rem; +} + +h2 { + font-weight: normal; + font-size: 225%; + color: #3c6fbd; +} +h3 { + color: rgba(0,0,0,0.87); + font-size: 1.7rem; + font-weight: 50; +} +/* banner */ +.header-banner-color{ + background-color: #3c6fbd; + margin: 0 -9999rem 20px -9999rem; + /* add back negative margin value */ + padding: 2.2rem 9999rem; +} +div.header-banner-text.container{ + color: white; + font-weight: lighter; + font-size: 320%; +} +div.header-banner-caption.container{ + font-weight: 300; + margin: 1.4rem 0 0.912rem 0; + color:#9EB8DE; + font-size: 32.5px; +} +/* banner Title-page only*/ +.header-banner-title-color{ + background-color: #3c6fbd; + margin: 0 -9999rem 20px -9999rem; + /* add back negative margin value */ + padding: 2.2rem 9999rem; +} +div.header-banner-title-text.container{ + color: white; + font-weight: lighter; + font-size: 320%; +} +div.header-banner-title-caption.container{ + font-weight: 300; + margin: 2.6rem 0 0.912rem 0; + color:white; + font-size: 32.5px; + text-align: center; +} +div.header-banner-title-button.container{ + position: relative; + cursor: pointer; + overflow: hidden; + padding: 3.3rem 0 .7rem 0; + top: 50%; +} +div.header-banner-title-button.container p{ + text-align:center; + color:#83cdfd; +} +/* footer Title-page only*/ +.footer-banner-title-color{ + background-color: #5c5757; + margin: -20px -9999rem 20px -9999rem; + padding: 1.5rem 9999rem; + color:#e6e6e6; + font-size: .85rem; +} +/* Download button Title page Only */ +.header-banner-title-color a { + color: white; + background: #03a9f4 ; + position: relative; + cursor: pointer; + display: block; + overflow: hidden; + vertical-align: middle; + -moz-user-select: none; + z-index: 1; + will-change: opacity, transform; + transition: all .3s ease-out; + padding: 1.4rem; + border-radius: 2px; + text-align: center; + letter-spacing: .5px; + border: none; + text-transform: uppercase; + font-family: "Roboto", sans-serif; + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); + font-size:125%; + margin:0 auto; + width: 300px; +} +.header-banner-title-color a:hover { /* Download button hover*/ + color: white; + background: #4fc3f7 ; + position: relative; + cursor: pointer; + display: block; + overflow: hidden; + vertical-align: middle; + -moz-user-select: none; + z-index: 1; + will-change: opacity, transform; + transition: all .3s ease-out; + padding: 1.4rem; + border-radius: 2px; + text-align: center; + letter-spacing: .5px; + border: none; + text-transform: uppercase; + font-family: "Roboto", sans-serif; + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); + font-size: .9rem; + font-size:125%; +} +.header-banner-title-color a:active { + background: #80d8ff ; + -webkit-transition: background 0.2s linear; + -moz-transition: background 0.2s linear; + -ms-transition: background 0.2s linear; + -o-transition: background 0.2s linear; + transition: background 0.2s linear; + font-size:125%; +} + +/* footer page button */ +a.btn.btn-neutral { + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); + font-family: "Roboto", sans-serif; +} +.rst-footer-buttons { + padding-bottom: 2em; +} + +/* Single row area*/ +div.row.container{ + display: table-row; +} + +/* 2 column page area*/ +div.two-caption.container{ + width: 50%; + margin-left: auto; + left: auto; + right: auto; + float: left; + box-sizing: border-box; + padding: 30px 0.75rem; + min-height: 1px; +} +div.two-caption.container p{ /*header caption */ + font-size: 175%; +} +div.two-text.container{ /*text */ + color: rgba(0,0,0,0.55); + font-size: 115%; + line-height: 1.6; +} +div.two-btn.container{ /*button */ + position: relative; + cursor: pointer; + display: inline-block; + overflow: hidden; + padding: 2rem 0; +} + +/* 3 column page area*/ +div.three-caption.container{ + width: 33.3333333333%; + margin-left: auto; + left: auto; + right: auto; + float: left; + box-sizing: border-box; + padding: 1em 0.75rem; + min-height: 1px; +} +div.three-caption.container p{ /*header caption */ + font-weight:bold; + font-size: 150%; +} +div.three-text.container{ /*text */ + padding-bottom: 1em; + color: rgba(0,0,0,0.55); +} + +/* 4 column page area*/ +div.four-caption.container{ + width: 25%; + margin-left: auto; + left: auto; + right: auto; + float: left; + box-sizing: border-box; + padding: 0 0.75rem; + min-height: 1px; +} + +/* Center table*/ +div.center-table.container{ + margin-left: auto; + margin-right: auto; + width: 50%; +} + +/* Admonition box*/ +.last { /* Admonition text box*/ + padding-left: 6px; + font-family: 'Inconsolata', Monaco, Consolas, 'Andale Mono', monospace; + font-size: 1rem; +} +.wy-alert-title, .rst-content .admonition-title, .admonition-title{ /* Admonition title box*/ + margin-bottom: 6px; + margin-left: -8px; + margin-right: -8px; + font-family: 'Inconsolata', Monaco, Consolas, 'Andale Mono', monospace; +} +.admonition.attention{ + padding: 8px; + background: #fff176; + font-family: "Roboto", sans-serif; + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); +} +.wy-alert.wy-alert-warning .wy-alert-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .attention .wy-alert-title, .rst-content .caution .wy-alert-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .admonition-todo .wy-alert-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .attention .admonition-title, .rst-content .caution .admonition-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .warning .admonition-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .admonition-todo .admonition-title{ + background: #fff176; + font-size:0; +} +.rst-content .admonition-title::before { + margin-right: 4px; + content: url(ic_clear_black_18dp_1x.png); +} + + + + +/* definition lists */ +.rst-content dl dt { + font-weight: unset; +} + +/* environment variables */ +.rst-content dl:not(.docutils) dt { + border-top: none; + background: white; +} +.rst-content dl:not(.docutils) dt code.descname{ + font-weight: 400; + font-family: "Roboto", sans-serif; + color: #26a69a; +} + +/*accent border */ +hr { + /*border-top: 2.5px solid #FAB208;*/ + display: none; +} + +/*toggle buttons for code snippets */ +.toggle.container { + padding-bottom:1.75rem; +} +.toggle .header { + color: white; + background: #313131; + position: relative; + cursor: pointer; + display: inline-block; + overflow: hidden; + vertical-align: middle; + -moz-user-select: none; + z-index: 1; + will-change: opacity, transform; + transition: all .3s ease-out; + padding: .9rem; + border-radius: 2px; + text-align: center; + letter-spacing: .5px; + border: none; + padding: .6rem 1.75rem; + text-transform: uppercase; + font-family: "Roboto", sans-serif; + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); + font-size: .9rem; +} +.toggle .header:hover { + color: white; + background: #515151; + position: relative; + cursor: pointer; + display: inline-block; + overflow: hidden; + vertical-align: middle; + -moz-user-select: none; + z-index: 1; + will-change: opacity, transform; + transition: all .3s ease-out; + padding: .9rem; + border-radius: 2px; + text-align: center; + letter-spacing: .5px; + border: none; + padding: .6rem 1.75rem; + text-transform: uppercase; + font-family: "Roboto", sans-serif; + box-shadow: 0 6px 10px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); + font-size: .9rem; +} +.toggle .header:active { + -webkit-transition: background 0.12s linear; + -moz-transition: background 0.12s linear; + -ms-transition: background 0.12s linear; + -o-transition: background 0.12s linear; + transition: background 0.12s linear; +} +.toggle .header.open { + color: white; + background: #3c6fbd; + position: relative; + cursor: pointer; + display: block; + overflow: hidden; + vertical-align: middle; + -moz-user-select: none; + z-index: 1; + will-change: opacity, transform; + transition: all .3s ease-out; + padding: .9rem; + border-radius: 2px; + text-align: center; + letter-spacing: .5px; + border: none; + padding: .6rem 1.75rem; + text-transform: uppercase; + font-family: "Roboto", sans-serif; + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); + font-size: .9rem; +} +.toggle .header.open:hover { + color: white; + background: #648ECE; + position: relative; + cursor: pointer; + display: block; + overflow: hidden; + vertical-align: middle; + -moz-user-select: none; + z-index: 1; + will-change: opacity, transform; + transition: all .3s ease-out; + padding: .9rem; + border-radius: 2px; + text-align: center; + letter-spacing: .5px; + border: none; + padding: .6rem 1.75rem; + text-transform: uppercase; + font-family: "Roboto", sans-serif; + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); + font-size: .9rem; +} +.toggle .header.open:active { + -webkit-transition: background 0.12s linear; + -moz-transition: background 0.12s linear; + -ms-transition: background 0.12s linear; + -o-transition: background 0.12s linear; + transition: background 0.12s linear; +} +code.xref.py.py-mod.docutils.literal{ /*rst mod attribute (i.e :mod:`action()`) */ + color: #638f20; + font-size: 95%; +} +code.docutils.literal{ /*rst `` attribute (i.e ``action`) `*/ + padding: 2px 4px; + border: none; + color: #72a424; + font-size: 90%; +} + +/*Help and Faq question format */ +div#help-and-faq.section strong{ + font-size: 22px; +} + +/*API section to address multi-button toggles */ +div#api-reference.section div.toggle.container{ + display:inline; +} +div#api-reference.section div.padding.container{ + padding-bottom: 1.3rem; +} +/* ------------------- Mobile Mode Only -------------------*/ +.wy-nav-top a { + display:none; +} +.wy-nav-top { + background: #3c6fbd; +} +.wy-nav-content-wrap .wy-nav-content { + padding-top: 0; +} \ No newline at end of file diff --git a/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff b/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 0000000..6cb6000 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 b/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 0000000..7059e23 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff b/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 0000000..f815f63 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 b/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 0000000..f2c76e5 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot b/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000..e9f60ca Binary files /dev/null and b/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.svg b/docs/_build/html/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000..855c845 --- /dev/null +++ b/docs/_build/html/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf b/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000..35acda2 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff b/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000..400014a Binary files /dev/null and b/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2 b/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000..4d13fc6 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/docs/_build/html/_static/css/fonts/lato-bold-italic.woff b/docs/_build/html/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 0000000..88ad05b Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-bold-italic.woff differ diff --git a/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2 b/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 0000000..c4e3d80 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/docs/_build/html/_static/css/fonts/lato-bold.woff b/docs/_build/html/_static/css/fonts/lato-bold.woff new file mode 100644 index 0000000..c6dff51 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-bold.woff differ diff --git a/docs/_build/html/_static/css/fonts/lato-bold.woff2 b/docs/_build/html/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 0000000..bb19504 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-bold.woff2 differ diff --git a/docs/_build/html/_static/css/fonts/lato-normal-italic.woff b/docs/_build/html/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 0000000..76114bc Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-normal-italic.woff differ diff --git a/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2 b/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 0000000..3404f37 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/docs/_build/html/_static/css/fonts/lato-normal.woff b/docs/_build/html/_static/css/fonts/lato-normal.woff new file mode 100644 index 0000000..ae1307f Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-normal.woff differ diff --git a/docs/_build/html/_static/css/fonts/lato-normal.woff2 b/docs/_build/html/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 0000000..3bf9843 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-normal.woff2 differ diff --git a/docs/_build/html/_static/css/ic_get_app_teal_18dp_2x.png b/docs/_build/html/_static/css/ic_get_app_teal_18dp_2x.png new file mode 100644 index 0000000..590ba9e Binary files /dev/null and b/docs/_build/html/_static/css/ic_get_app_teal_18dp_2x.png differ diff --git a/docs/_build/html/_static/css/ic_get_app_white_18dp_2x.png b/docs/_build/html/_static/css/ic_get_app_white_18dp_2x.png new file mode 100644 index 0000000..c8a2039 Binary files /dev/null and b/docs/_build/html/_static/css/ic_get_app_white_18dp_2x.png differ diff --git a/docs/_build/html/_static/css/saws.scc b/docs/_build/html/_static/css/saws.scc new file mode 100644 index 0000000..891496c Binary files /dev/null and b/docs/_build/html/_static/css/saws.scc differ diff --git a/docs/_build/html/_static/css/theme.css b/docs/_build/html/_static/css/theme.css new file mode 100644 index 0000000..aed8cef --- /dev/null +++ b/docs/_build/html/_static/css/theme.css @@ -0,0 +1,6 @@ +/* sphinx_rtd_theme version 0.4.3 | MIT license */ +/* Built 20190212 16:02 */ +*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:.5cm}p,h2,.rst-content .toctree-wrapper p.caption,h3{orphans:3;widows:3}h2,.rst-content .toctree-wrapper p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content .code-block-caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.7.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"),url("../fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857em;text-align:center}.fa-ul{padding-left:0;margin-left:2.1428571429em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.1428571429em;width:2.1428571429em;top:.1428571429em;text-align:center}.fa-li.fa-lg{left:-1.8571428571em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.wy-menu-vertical li span.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-left.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-left.toctree-expand,.rst-content .fa-pull-left.admonition-title,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content dl dt .fa-pull-left.headerlink,.rst-content p.caption .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.rst-content code.download span.fa-pull-left:first-child,.fa-pull-left.icon{margin-right:.3em}.fa.fa-pull-right,.wy-menu-vertical li span.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-right.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-right.toctree-expand,.rst-content .fa-pull-right.admonition-title,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content dl dt .fa-pull-right.headerlink,.rst-content p.caption .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.rst-content code.download span.fa-pull-right:first-child,.fa-pull-right.icon{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content .code-block-caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content .code-block-caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-hotel:before,.fa-bed:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-yc:before,.fa-y-combinator:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-tv:before,.fa-television:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:""}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-signing:before,.fa-sign-language:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-vcard:before,.fa-address-card:before{content:""}.fa-vcard-o:before,.fa-address-card-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content .code-block-caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content table>caption .headerlink,.rst-content table>caption a .headerlink,a .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content table>caption .headerlink,.rst-content table>caption .btn .headerlink,.btn .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content table>caption .headerlink,.rst-content table>caption .nav .headerlink,.nav .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.btn .rst-content .code-block-caption .fa-large.headerlink,.rst-content .code-block-caption .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.nav .rst-content .code-block-caption .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.btn .rst-content .code-block-caption .fa-spin.headerlink,.rst-content .code-block-caption .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.nav .rst-content .code-block-caption .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.admonition{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo,.rst-content .wy-alert-warning.admonition{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title,.rst-content .wy-alert-warning.admonition .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.admonition{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.admonition{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.admonition{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-neutral:visited{color:#404040 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 .3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.wy-control-group .wy-form-full input[type="search"],.wy-control-group .wy-form-full input[type="tel"],.wy-control-group .wy-form-full input[type="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.wy-control-group .wy-form-halves input[type="search"],.wy-control-group .wy-form-halves input[type="tel"],.wy-control-group .wy-form-halves input[type="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.wy-control-group .wy-form-thirds input[type="search"],.wy-control-group .wy-form-thirds input[type="tel"],.wy-control-group .wy-form-thirds input[type="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.3576515979%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.3576515979%;width:48.821174201%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.3576515979%;width:31.7615656014%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type="datetime-local"]{padding:.34375em .625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{position:absolute;content:"";display:block;left:0;top:0;width:36px;height:12px;border-radius:4px;background:#ccc;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27AE60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:.3em;display:block}.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980B9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9B59B6}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,.rst-content .toctree-wrapper p.caption,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content .toctree-wrapper p.caption{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:before,.wy-breadcrumbs:after{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs li code,.wy-breadcrumbs li .rst-content tt,.rst-content .wy-breadcrumbs li tt{padding:5px;border:none;background:none}.wy-breadcrumbs li code.literal,.wy-breadcrumbs li .rst-content tt.literal,.rst-content .wy-breadcrumbs li tt.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#3a7ca8;height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin:12px 0 0 0;display:block;font-weight:bold;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a{color:#404040}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980B9;text-align:center;padding:.809em;display:block;color:#fcfcfc;margin-bottom:.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:normal;color:rgba(255,255,255,0.3)}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:gray}footer p{margin-bottom:12px}footer span.commit code,footer span.commit .rst-content tt,.rst-content footer span.commit tt{padding:0px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:1em;background:none;border:none;color:gray}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{width:100%}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:before,.rst-breadcrumbs-buttons:after{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-side-scroll{width:auto}.wy-side-nav-search{width:auto}.wy-menu.wy-menu-vertical{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1100px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content img{max-width:100%;height:auto}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure p:last-child.caption{margin-bottom:0px}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;display:block;overflow:auto}.rst-content pre.literal-block,.rst-content div[class^='highlight']{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px 0}.rst-content pre.literal-block div[class^='highlight'],.rst-content div[class^='highlight'] div[class^='highlight']{padding:0px;border:none;margin:0}.rst-content div[class^='highlight'] td.code{width:100%}.rst-content .linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;display:block;overflow:auto}.rst-content div[class^='highlight'] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content pre.literal-block,.rst-content div[class^='highlight'] pre,.rst-content .linenodiv pre{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:12px;line-height:1.4}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^='highlight'],.rst-content div[class^='highlight'] pre{white-space:pre-wrap}}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last,.rst-content .admonition .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .section ol p:last-child,.rst-content .section ul p:last-child{margin-bottom:24px}.rst-content .line-block{margin-left:0px;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content .toctree-wrapper p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink{visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content .toctree-wrapper p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after,.rst-content table>caption .headerlink:after,.rst-content .code-block-caption .headerlink:after{content:"";font-family:FontAwesome}.rst-content h1:hover .headerlink:after,.rst-content h2:hover .headerlink:after,.rst-content .toctree-wrapper p.caption:hover .headerlink:after,.rst-content h3:hover .headerlink:after,.rst-content h4:hover .headerlink:after,.rst-content h5:hover .headerlink:after,.rst-content h6:hover .headerlink:after,.rst-content dl dt:hover .headerlink:after,.rst-content p.caption:hover .headerlink:after,.rst-content table>caption:hover .headerlink:after,.rst-content .code-block-caption:hover .headerlink:after{visibility:visible}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:baseline;position:relative;top:-0.4em;line-height:0;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:gray}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.docutils.citation tt,.rst-content table.docutils.citation code,.rst-content table.docutils.footnote tt,.rst-content table.docutils.footnote code{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}.rst-content table.docutils td .last,.rst-content table.docutils td .last :last-child{margin-bottom:0}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none}.rst-content table.field-list td p{font-size:inherit;line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content tt,.rst-content tt,.rst-content code{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;padding:2px 5px}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal{color:#E74C3C}.rst-content tt.xref,a .rst-content tt,.rst-content tt.xref,.rst-content code.xref,a .rst-content tt,a .rst-content code{font-weight:bold;color:#404040}.rst-content pre,.rst-content kbd,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold;margin-bottom:12px}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:#555}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-weight:normal;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child,.rst-content code.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-regular.eot");src:url("../fonts/Lato/lato-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-regular.woff2") format("woff2"),url("../fonts/Lato/lato-regular.woff") format("woff"),url("../fonts/Lato/lato-regular.ttf") format("truetype");font-weight:400;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-bold.eot");src:url("../fonts/Lato/lato-bold.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-bold.woff2") format("woff2"),url("../fonts/Lato/lato-bold.woff") format("woff"),url("../fonts/Lato/lato-bold.ttf") format("truetype");font-weight:700;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-bolditalic.eot");src:url("../fonts/Lato/lato-bolditalic.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-bolditalic.woff2") format("woff2"),url("../fonts/Lato/lato-bolditalic.woff") format("woff"),url("../fonts/Lato/lato-bolditalic.ttf") format("truetype");font-weight:700;font-style:italic}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-italic.eot");src:url("../fonts/Lato/lato-italic.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-italic.woff2") format("woff2"),url("../fonts/Lato/lato-italic.woff") format("woff"),url("../fonts/Lato/lato-italic.ttf") format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:url("../fonts/RobotoSlab/roboto-slab.eot");src:url("../fonts/RobotoSlab/roboto-slab-v7-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff2") format("woff2"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff") format("woff"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.ttf") format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot");src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot?#iefix") format("embedded-opentype"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff2") format("woff2"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff") format("woff"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.ttf") format("truetype")} diff --git a/docs/_build/html/_static/doctools.js b/docs/_build/html/_static/doctools.js new file mode 100644 index 0000000..344db17 --- /dev/null +++ b/docs/_build/html/_static/doctools.js @@ -0,0 +1,315 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + 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); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * 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 + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + 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); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/docs/_build/html/_static/documentation_options.js b/docs/_build/html/_static/documentation_options.js new file mode 100644 index 0000000..7b7573c --- /dev/null +++ b/docs/_build/html/_static/documentation_options.js @@ -0,0 +1,10 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '2.0.22', + LANGUAGE: 'None', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, +}; \ No newline at end of file diff --git a/docs/_build/html/_static/down-pressed.png b/docs/_build/html/_static/down-pressed.png new file mode 100644 index 0000000..5756c8c Binary files /dev/null and b/docs/_build/html/_static/down-pressed.png differ diff --git a/docs/_build/html/_static/down.png b/docs/_build/html/_static/down.png new file mode 100644 index 0000000..1b3bdad Binary files /dev/null and b/docs/_build/html/_static/down.png differ diff --git a/docs/_build/html/_static/file.png b/docs/_build/html/_static/file.png new file mode 100644 index 0000000..a858a41 Binary files /dev/null and b/docs/_build/html/_static/file.png differ diff --git a/docs/_build/html/_static/fonts/Inconsolata-Bold.ttf b/docs/_build/html/_static/fonts/Inconsolata-Bold.ttf new file mode 100644 index 0000000..809c1f5 Binary files /dev/null and b/docs/_build/html/_static/fonts/Inconsolata-Bold.ttf differ diff --git a/docs/_build/html/_static/fonts/Inconsolata-Regular.ttf b/docs/_build/html/_static/fonts/Inconsolata-Regular.ttf new file mode 100644 index 0000000..fc981ce Binary files /dev/null and b/docs/_build/html/_static/fonts/Inconsolata-Regular.ttf differ diff --git a/docs/_build/html/_static/fonts/Inconsolata.ttf b/docs/_build/html/_static/fonts/Inconsolata.ttf new file mode 100644 index 0000000..4b8a36d Binary files /dev/null and b/docs/_build/html/_static/fonts/Inconsolata.ttf differ diff --git a/docs/_build/html/_static/fonts/Lato-Bold.ttf b/docs/_build/html/_static/fonts/Lato-Bold.ttf new file mode 100644 index 0000000..1d23c70 Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato-Bold.ttf differ diff --git a/docs/_build/html/_static/fonts/Lato-Regular.ttf b/docs/_build/html/_static/fonts/Lato-Regular.ttf new file mode 100644 index 0000000..0f3d0f8 Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato-Regular.ttf differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bold.eot b/docs/_build/html/_static/fonts/Lato/lato-bold.eot new file mode 100644 index 0000000..3361183 Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-bold.eot differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bold.ttf b/docs/_build/html/_static/fonts/Lato/lato-bold.ttf new file mode 100644 index 0000000..29f691d Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-bold.ttf differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bold.woff b/docs/_build/html/_static/fonts/Lato/lato-bold.woff new file mode 100644 index 0000000..c6dff51 Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-bold.woff differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bold.woff2 b/docs/_build/html/_static/fonts/Lato/lato-bold.woff2 new file mode 100644 index 0000000..bb19504 Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-bold.woff2 differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bolditalic.eot b/docs/_build/html/_static/fonts/Lato/lato-bolditalic.eot new file mode 100644 index 0000000..3d41549 Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-bolditalic.eot differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bolditalic.ttf b/docs/_build/html/_static/fonts/Lato/lato-bolditalic.ttf new file mode 100644 index 0000000..f402040 Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-bolditalic.ttf differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff b/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff new file mode 100644 index 0000000..88ad05b Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 b/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 new file mode 100644 index 0000000..c4e3d80 Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-italic.eot b/docs/_build/html/_static/fonts/Lato/lato-italic.eot new file mode 100644 index 0000000..3f82642 Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-italic.eot differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-italic.ttf b/docs/_build/html/_static/fonts/Lato/lato-italic.ttf new file mode 100644 index 0000000..b4bfc9b Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-italic.ttf differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-italic.woff b/docs/_build/html/_static/fonts/Lato/lato-italic.woff new file mode 100644 index 0000000..76114bc Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-italic.woff differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-italic.woff2 b/docs/_build/html/_static/fonts/Lato/lato-italic.woff2 new file mode 100644 index 0000000..3404f37 Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-italic.woff2 differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-regular.eot b/docs/_build/html/_static/fonts/Lato/lato-regular.eot new file mode 100644 index 0000000..11e3f2a Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-regular.eot differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-regular.ttf b/docs/_build/html/_static/fonts/Lato/lato-regular.ttf new file mode 100644 index 0000000..74decd9 Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-regular.ttf differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-regular.woff b/docs/_build/html/_static/fonts/Lato/lato-regular.woff new file mode 100644 index 0000000..ae1307f Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-regular.woff differ diff --git a/docs/_build/html/_static/fonts/Lato/lato-regular.woff2 b/docs/_build/html/_static/fonts/Lato/lato-regular.woff2 new file mode 100644 index 0000000..3bf9843 Binary files /dev/null and b/docs/_build/html/_static/fonts/Lato/lato-regular.woff2 differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab-Bold.ttf b/docs/_build/html/_static/fonts/RobotoSlab-Bold.ttf new file mode 100644 index 0000000..df5d1df Binary files /dev/null and b/docs/_build/html/_static/fonts/RobotoSlab-Bold.ttf differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab-Regular.ttf b/docs/_build/html/_static/fonts/RobotoSlab-Regular.ttf new file mode 100644 index 0000000..eb52a79 Binary files /dev/null and b/docs/_build/html/_static/fonts/RobotoSlab-Regular.ttf differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot new file mode 100644 index 0000000..79dc8ef Binary files /dev/null and b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf new file mode 100644 index 0000000..df5d1df Binary files /dev/null and b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff new file mode 100644 index 0000000..6cb6000 Binary files /dev/null and b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 new file mode 100644 index 0000000..7059e23 Binary files /dev/null and b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot new file mode 100644 index 0000000..2f7ca78 Binary files /dev/null and b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf new file mode 100644 index 0000000..eb52a79 Binary files /dev/null and b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff new file mode 100644 index 0000000..f815f63 Binary files /dev/null and b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff differ diff --git a/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 new file mode 100644 index 0000000..f2c76e5 Binary files /dev/null and b/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 differ diff --git a/docs/_build/html/_static/fonts/fontawesome-webfont.eot b/docs/_build/html/_static/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000..e9f60ca Binary files /dev/null and b/docs/_build/html/_static/fonts/fontawesome-webfont.eot differ diff --git a/docs/_build/html/_static/fonts/fontawesome-webfont.svg b/docs/_build/html/_static/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000..855c845 --- /dev/null +++ b/docs/_build/html/_static/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_build/html/_static/fonts/fontawesome-webfont.ttf b/docs/_build/html/_static/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000..35acda2 Binary files /dev/null and b/docs/_build/html/_static/fonts/fontawesome-webfont.ttf differ diff --git a/docs/_build/html/_static/fonts/fontawesome-webfont.woff b/docs/_build/html/_static/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000..400014a Binary files /dev/null and b/docs/_build/html/_static/fonts/fontawesome-webfont.woff differ diff --git a/docs/_build/html/_static/fonts/fontawesome-webfont.woff2 b/docs/_build/html/_static/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000..4d13fc6 Binary files /dev/null and b/docs/_build/html/_static/fonts/fontawesome-webfont.woff2 differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Bold.eot b/docs/_build/html/_static/fonts/roboto/Roboto-Bold.eot new file mode 100644 index 0000000..b73776e Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Bold.eot differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Bold.ttf b/docs/_build/html/_static/fonts/roboto/Roboto-Bold.ttf new file mode 100644 index 0000000..68822ca Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Bold.ttf differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Bold.woff b/docs/_build/html/_static/fonts/roboto/Roboto-Bold.woff new file mode 100644 index 0000000..1f75afd Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Bold.woff differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Bold.woff2 b/docs/_build/html/_static/fonts/roboto/Roboto-Bold.woff2 new file mode 100644 index 0000000..350d1c3 Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Bold.woff2 differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Light.eot b/docs/_build/html/_static/fonts/roboto/Roboto-Light.eot new file mode 100644 index 0000000..072cdc4 Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Light.eot differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Light.ttf b/docs/_build/html/_static/fonts/roboto/Roboto-Light.ttf new file mode 100644 index 0000000..aa45340 Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Light.ttf differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Light.woff b/docs/_build/html/_static/fonts/roboto/Roboto-Light.woff new file mode 100644 index 0000000..3480c6c Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Light.woff differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Light.woff2 b/docs/_build/html/_static/fonts/roboto/Roboto-Light.woff2 new file mode 100644 index 0000000..9a4d98c Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Light.woff2 differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Medium.eot b/docs/_build/html/_static/fonts/roboto/Roboto-Medium.eot new file mode 100644 index 0000000..f9ad995 Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Medium.eot differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Medium.ttf b/docs/_build/html/_static/fonts/roboto/Roboto-Medium.ttf new file mode 100644 index 0000000..a3c1a1f Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Medium.ttf differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Medium.woff b/docs/_build/html/_static/fonts/roboto/Roboto-Medium.woff new file mode 100644 index 0000000..1186773 Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Medium.woff differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Medium.woff2 b/docs/_build/html/_static/fonts/roboto/Roboto-Medium.woff2 new file mode 100644 index 0000000..d10a592 Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Medium.woff2 differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Regular.eot b/docs/_build/html/_static/fonts/roboto/Roboto-Regular.eot new file mode 100644 index 0000000..9b5e8e4 Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Regular.eot differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Regular.ttf b/docs/_build/html/_static/fonts/roboto/Roboto-Regular.ttf new file mode 100644 index 0000000..0e58508 Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Regular.ttf differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Regular.woff b/docs/_build/html/_static/fonts/roboto/Roboto-Regular.woff new file mode 100644 index 0000000..f823258 Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Regular.woff differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Regular.woff2 b/docs/_build/html/_static/fonts/roboto/Roboto-Regular.woff2 new file mode 100644 index 0000000..b7082ef Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Regular.woff2 differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Thin.eot b/docs/_build/html/_static/fonts/roboto/Roboto-Thin.eot new file mode 100644 index 0000000..2284a3b Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Thin.eot differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Thin.ttf b/docs/_build/html/_static/fonts/roboto/Roboto-Thin.ttf new file mode 100644 index 0000000..8779333 Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Thin.ttf differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Thin.woff b/docs/_build/html/_static/fonts/roboto/Roboto-Thin.woff new file mode 100644 index 0000000..2a98c1e Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Thin.woff differ diff --git a/docs/_build/html/_static/fonts/roboto/Roboto-Thin.woff2 b/docs/_build/html/_static/fonts/roboto/Roboto-Thin.woff2 new file mode 100644 index 0000000..a38025a Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/Roboto-Thin.woff2 differ diff --git a/docs/_build/html/_static/fonts/roboto/saws.scc b/docs/_build/html/_static/fonts/roboto/saws.scc new file mode 100644 index 0000000..58b9dc2 Binary files /dev/null and b/docs/_build/html/_static/fonts/roboto/saws.scc differ diff --git a/docs/_build/html/_static/jquery-3.2.1.js b/docs/_build/html/_static/jquery-3.2.1.js new file mode 100644 index 0000000..d2d8ca4 --- /dev/null +++ b/docs/_build/html/_static/jquery-3.2.1.js @@ -0,0 +1,10253 @@ +/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +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; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // 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 ( i === length ) { + 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 = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.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( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return 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 ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + 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 + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, 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 || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = 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).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "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; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ 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 = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // 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( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * 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( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + 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; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // 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, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // 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.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +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 ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + 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, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + 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 elem; + } + + 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 elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + 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; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, 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 + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = 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" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // 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: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( 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; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // 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; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.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 ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + 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 + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = 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; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( 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.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // 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; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/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; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + 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 ( 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 ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.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 = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // 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; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + 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; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.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 ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !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 ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // 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( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // 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 ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && 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) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === 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( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + 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 ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + +
+

Opening library documentation failed

+
    +
  • Verify that you have JavaScript enabled in your browser.
  • +
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • +
  • Check are there messages in your browser's JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • +
+
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_build/html/_static/operations/saws.scc b/docs/_build/html/_static/operations/saws.scc new file mode 100644 index 0000000..dff32a9 Binary files /dev/null and b/docs/_build/html/_static/operations/saws.scc differ diff --git a/docs/_build/html/_static/plus.png b/docs/_build/html/_static/plus.png new file mode 100644 index 0000000..7107cec Binary files /dev/null and b/docs/_build/html/_static/plus.png differ diff --git a/docs/_build/html/_static/pygments.css b/docs/_build/html/_static/pygments.css new file mode 100644 index 0000000..20c4814 --- /dev/null +++ b/docs/_build/html/_static/pygments.css @@ -0,0 +1,69 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/_build/html/_static/searchtools.js b/docs/_build/html/_static/searchtools.js new file mode 100644 index 0000000..5ff3180 --- /dev/null +++ b/docs/_build/html/_static/searchtools.js @@ -0,0 +1,481 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +if (!Scorer) { + /** + * Simple result scoring code. + */ + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [filename, title, anchor, descr, score] + // and returns the new score. + /* + score: function(result) { + return result[4]; + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: {0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5}, // used to be unimportantResults + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + // query found in terms + term: 5 + }; +} + +if (!splitQuery) { + function splitQuery(query) { + return query.split(/\s+/); + } +} + +/** + * Search Module + */ +var Search = { + + _index : null, + _queued_query : null, + _pulse_status : -1, + + init : function() { + var params = $.getQueryParameters(); + if (params.q) { + var query = params.q[0]; + $('input[name="q"]')[0].value = query; + this.performSearch(query); + } + }, + + loadIndex : function(url) { + $.ajax({type: "GET", url: url, data: null, + dataType: "script", cache: true, + complete: function(jqxhr, textstatus) { + if (textstatus != "success") { + document.getElementById("searchindexloader").src = url; + } + }}); + }, + + setIndex : function(index) { + var q; + this._index = index; + if ((q = this._queued_query) !== null) { + this._queued_query = null; + Search.query(q); + } + }, + + hasIndex : function() { + return this._index !== null; + }, + + deferQuery : function(query) { + this._queued_query = query; + }, + + stopPulse : function() { + this._pulse_status = 0; + }, + + startPulse : function() { + if (this._pulse_status >= 0) + return; + function pulse() { + var i; + Search._pulse_status = (Search._pulse_status + 1) % 4; + var dotString = ''; + for (i = 0; i < Search._pulse_status; i++) + dotString += '.'; + Search.dots.text(dotString); + if (Search._pulse_status > -1) + window.setTimeout(pulse, 500); + } + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch : function(query) { + // create the required interface elements + this.out = $('#search-results'); + this.title = $('

' + _('Searching') + '

').appendTo(this.out); + this.dots = $('').appendTo(this.title); + this.status = $('

').appendTo(this.out); + this.output = $('