浏览代码

Add Victoria School

Michael Tang 4 年之前
父节点
当前提交
d8ff3156e4
共有 100 个文件被更改,包括 11880 次插入0 次删除
  1. 二进制
      .DS_Store
  2. 0 0
      401.py
  3. 0 0
      \
  4. 0 0
      bcit.py
  5. 二进制
      chromedriver
  6. 0 0
      google-chrome-stable_current_amd64.deb
  7. 0 0
      newegg.py
  8. 二进制
      selenium-3.141.0.tar.gz
  9. 672 0
      selenium-3.141.0/CHANGES
  10. 202 0
      selenium-3.141.0/LICENSE
  11. 22 0
      selenium-3.141.0/MANIFEST.in
  12. 168 0
      selenium-3.141.0/PKG-INFO
  13. 145 0
      selenium-3.141.0/README.rst
  14. 19 0
      selenium-3.141.0/build/lib/selenium/__init__.py
  15. 18 0
      selenium-3.141.0/build/lib/selenium/common/__init__.py
  16. 327 0
      selenium-3.141.0/build/lib/selenium/common/exceptions.py
  17. 39 0
      selenium-3.141.0/build/lib/selenium/webdriver/__init__.py
  18. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/android/__init__.py
  19. 42 0
      selenium-3.141.0/build/lib/selenium/webdriver/android/webdriver.py
  20. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/blackberry/__init__.py
  21. 116 0
      selenium-3.141.0/build/lib/selenium/webdriver/blackberry/webdriver.py
  22. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/chrome/__init__.py
  23. 211 0
      selenium-3.141.0/build/lib/selenium/webdriver/chrome/options.py
  24. 28 0
      selenium-3.141.0/build/lib/selenium/webdriver/chrome/remote_connection.py
  25. 45 0
      selenium-3.141.0/build/lib/selenium/webdriver/chrome/service.py
  26. 161 0
      selenium-3.141.0/build/lib/selenium/webdriver/chrome/webdriver.py
  27. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/__init__.py
  28. 363 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/action_chains.py
  29. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/actions/__init__.py
  30. 85 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/actions/action_builder.py
  31. 43 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/actions/input_device.py
  32. 50 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/actions/interaction.py
  33. 50 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/actions/key_actions.py
  34. 51 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/actions/key_input.py
  35. 5 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/actions/mouse_button.py
  36. 100 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/actions/pointer_actions.py
  37. 63 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/actions/pointer_input.py
  38. 105 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/alert.py
  39. 35 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/by.py
  40. 128 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/desired_capabilities.py
  41. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/html5/__init__.py
  42. 48 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/html5/application_cache.py
  43. 96 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/keys.py
  44. 334 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/proxy.py
  45. 178 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/service.py
  46. 192 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/touch_actions.py
  47. 152 0
      selenium-3.141.0/build/lib/selenium/webdriver/common/utils.py
  48. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/edge/__init__.py
  49. 54 0
      selenium-3.141.0/build/lib/selenium/webdriver/edge/options.py
  50. 57 0
      selenium-3.141.0/build/lib/selenium/webdriver/edge/service.py
  51. 71 0
      selenium-3.141.0/build/lib/selenium/webdriver/edge/webdriver.py
  52. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/__init__.py
  53. 二进制
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/amd64/x_ignore_nofocus.so
  54. 84 0
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/extension_connection.py
  55. 217 0
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/firefox_binary.py
  56. 408 0
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/firefox_profile.py
  57. 189 0
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/options.py
  58. 34 0
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/remote_connection.py
  59. 54 0
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/service.py
  60. 276 0
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/webdriver.py
  61. 二进制
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/webdriver.xpi
  62. 69 0
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/webdriver_prefs.json
  63. 49 0
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/webelement.py
  64. 二进制
      selenium-3.141.0/build/lib/selenium/webdriver/firefox/x86/x_ignore_nofocus.so
  65. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/ie/__init__.py
  66. 351 0
      selenium-3.141.0/build/lib/selenium/webdriver/ie/options.py
  67. 50 0
      selenium-3.141.0/build/lib/selenium/webdriver/ie/service.py
  68. 105 0
      selenium-3.141.0/build/lib/selenium/webdriver/ie/webdriver.py
  69. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/opera/__init__.py
  70. 115 0
      selenium-3.141.0/build/lib/selenium/webdriver/opera/options.py
  71. 83 0
      selenium-3.141.0/build/lib/selenium/webdriver/opera/webdriver.py
  72. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/phantomjs/__init__.py
  73. 68 0
      selenium-3.141.0/build/lib/selenium/webdriver/phantomjs/service.py
  74. 80 0
      selenium-3.141.0/build/lib/selenium/webdriver/phantomjs/webdriver.py
  75. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/remote/__init__.py
  76. 173 0
      selenium-3.141.0/build/lib/selenium/webdriver/remote/command.py
  77. 245 0
      selenium-3.141.0/build/lib/selenium/webdriver/remote/errorhandler.py
  78. 58 0
      selenium-3.141.0/build/lib/selenium/webdriver/remote/file_detector.py
  79. 8 0
      selenium-3.141.0/build/lib/selenium/webdriver/remote/getAttribute.js
  80. 101 0
      selenium-3.141.0/build/lib/selenium/webdriver/remote/isDisplayed.js
  81. 85 0
      selenium-3.141.0/build/lib/selenium/webdriver/remote/mobile.py
  82. 441 0
      selenium-3.141.0/build/lib/selenium/webdriver/remote/remote_connection.py
  83. 134 0
      selenium-3.141.0/build/lib/selenium/webdriver/remote/switch_to.py
  84. 90 0
      selenium-3.141.0/build/lib/selenium/webdriver/remote/utils.py
  85. 1262 0
      selenium-3.141.0/build/lib/selenium/webdriver/remote/webdriver.py
  86. 708 0
      selenium-3.141.0/build/lib/selenium/webdriver/remote/webelement.py
  87. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/safari/__init__.py
  88. 28 0
      selenium-3.141.0/build/lib/selenium/webdriver/safari/permissions.py
  89. 27 0
      selenium-3.141.0/build/lib/selenium/webdriver/safari/remote_connection.py
  90. 64 0
      selenium-3.141.0/build/lib/selenium/webdriver/safari/service.py
  91. 113 0
      selenium-3.141.0/build/lib/selenium/webdriver/safari/webdriver.py
  92. 16 0
      selenium-3.141.0/build/lib/selenium/webdriver/support/__init__.py
  93. 79 0
      selenium-3.141.0/build/lib/selenium/webdriver/support/abstract_event_listener.py
  94. 310 0
      selenium-3.141.0/build/lib/selenium/webdriver/support/color.py
  95. 322 0
      selenium-3.141.0/build/lib/selenium/webdriver/support/event_firing_webdriver.py
  96. 19 0
      selenium-3.141.0/build/lib/selenium/webdriver/support/events.py
  97. 422 0
      selenium-3.141.0/build/lib/selenium/webdriver/support/expected_conditions.py
  98. 241 0
      selenium-3.141.0/build/lib/selenium/webdriver/support/select.py
  99. 19 0
      selenium-3.141.0/build/lib/selenium/webdriver/support/ui.py
  100. 0 0
      selenium-3.141.0/build/lib/selenium/webdriver/support/wait.py

二进制
.DS_Store


+ 0 - 0
401.py


+ 0 - 0
\


+ 0 - 0
bcit.py


二进制
chromedriver


+ 0 - 0
google-chrome-stable_current_amd64.deb


+ 0 - 0
newegg.py


二进制
selenium-3.141.0.tar.gz


+ 672 - 0
selenium-3.141.0/CHANGES

@@ -0,0 +1,672 @@
+Selenium 3.141.0
+* Bump version to a better approximation of Π
+* Improved Test build targets
+* fix os path in test for Windows
+* use 'NUL' for /dev/null on Windows
+* Update ctor docstrings to explain that a directory passed in is cloned. Fixes #6542
+* Allow passing of service_args to Safari. Fixes #6459
+* Remove element equals url
+* Improved WebExtension support
+
+Selenium 3.14.1
+* Fix ability to set timeout for urllib3 (#6286)
+* get_cookie uses w3c endpoint when compliant
+* Remove body from GET requests (#6250)
+* Fix actions pause for fraction of a second (#6300)
+* Fixed input pausing for some actions methods
+* Capabilities can be set on Options classes
+* WebElement rect method is now forward compatible for OSS endpoints (#6355)
+* Deprecation warnings now have a stacklevel of 2
+* keep_alive can now be set on Webdriver init (#6316)
+* isDisplayed atom is now used for all w3c compliant browser, fixing issue with Safari 12
+
+Selenium 3.14.0
+* Fix doc of URL-related ExpectedCondition (#6236)
+* Added ExpectedCondition invisibility_of_element
+* Swap out httplib for urllib3
+* Be consistent with webdriver init kwarg service_log_path (#5725)
+
+Selenium 3.13.0
+
+* Add executing Chrome devtools command (#5989)
+* fix incorrect w3c action encoding in python client (#6014)
+* Implement context manager for WebDriver
+* Stop sending "windowHandle" param in maximize_window command for w3c
+
+Selenium 3.12.0
+
+* Add desired_capabilities keyword to IE and Firefox drivers for driver consitency
+* Fix bug with creating Safari webdriver instance (#5578)
+* Add support for Safari extension command
+* Deprecate Options `set_headless` methods in favor of property setter
+* Only set --disable-gpu for Chrome headless when on Windows
+* Add selenium User-Agent header (#5696)
+* Remote webdriver can now be started when passing options
+* All Options.to_capabilities now start with default DesiredCapabilities
+* Improve the error message that is raised when safaridriver cannot be found (#5739)
+* IeOptions class is now imported to selenium.webdriver
+* Remove the beta `authenticate` methods from `Alert`
+
+Selenium 3.11.0
+
+No changes just keeping python version in step with the rest of the project.
+
+Selenium 3.10.0
+
+* make tests to check clicking on disabled element work for w3c compliant drivers (#5561)
+* add docstring for InvalidElementStateException. Fixes #5520
+* Deleting unused imports
+* Making python specification in IDEA project more generic
+* It should be possible to use a custom safaridriver executable to run Selenium's test suite.
+
+Selenium 3.9.0
+
+* Add docstrings to WebElement find methods (#5384)
+* Additional data in unexpected alert error is now handled for w3c drivers (#5416)
+* Allow service_args to be passed into Firefox WebDriver (#5421)
+* Fix bug introduced with response logging in 3.8.1 (#5362)
+
+Selenium 3.8.1
+
+* Fix bug when creating an Opera driver (#5266)
+* Stop sending sessionId in w3c payload. (#4620)
+* Fix issue with w3c actions releasing on element (#5180)
+* A more descriptive log message is displayed if the port cannot be connected (#2913)
+* Initialize Alert object by calling alert.text (#1863)
+* PhantomJS is now deprecated, please use either Chrome or Firefox in headless mode
+* Legacy Firefox driver: ensuring copy of profile dir, its 'extensions' subdir and 'user.js' file are writable. (#1466)
+
+Selenium 3.8.0
+
+* Firefox options can now be imported from selenium.webdriver as FirefoxOptions (#5120)
+* Headless mode can now be set in Chrome Options using `set_headless`
+* Headless mode can now be set in Firefox Options using `set_headless`
+* Add the WebKitGTK WebDriver and options class (#4635)
+* Browser options can now be passed to remote WebDriver via the `options` parameter
+* Browser option parameters are now standardized across drivers as `options`. `firefox_options`,
+  `chrome_options`, and `ie_options` are now deprecated
+* Added missing W3C Error Codes (#4556)
+* Support has been removed for Python versions 2.6 and 3.3
+
+Selenium 3.7.0
+
+* need to pass applicable environment variables to tox
+* Fix active_element for w3c drivers (#3979)
+* add support for minimize command
+* add support for fullscreen command
+* window rect commands should fail on firefox and remote (legacy)
+* Fix python backward compatibility for window commands (#4937)
+* Update docstrings to specify the type of path needed to install firefox addons. (#4881)
+* Update python chromeOptions key for capabilities (#4622)
+* Fix python pause action implementation (#4795)
+
+Selenium 3.6.0
+
+* Fix package name in python webelement module (#4670)
+* Fix python driver examples (#3872)
+* No need to multiply pause by 1000
+* Add pause to action chains
+* only check for proxyType once
+* lowercase proxy type for w3c payload in python #4574
+* guarding against null return value from find_elements in python #4555
+* remove unnecessary pytest marking, address flake8 issues
+* allow IE WebDriver to accept IE Options
+* add IE Options class
+* convert OSS capabilities to W3C equivalent for W3C payload
+* Add Safari to API docs
+
+Selenium 3.5.0
+
+* Numerous test fixes
+*Iterate over capabilities in a way to support py2.7 and py3
+* Fix W3C switching to window by name.
+* Support GeckoDriver addon install/uninstall commands  #4215.
+* Move firefox_profile into moz:firefoxOptions.
+* Filter non-W3C capability names out of alwaysMatch.
+* Honor cmd line args passed to Service ctor (#4167)
+* Add expected conditions based on URL to Python Expected Conditions #4160
+* Add network emulation to Chrome Python bindings (#4011)
+* add warning when saving incorrectly named screenshot (#4141)
+
+Selenium 3.4.3
+* Fix EventFiringWebdriver and WebElement to raise AttributeError on missing attributes. (#4107)
+* unwrap WebElements inside dicts
+
+Selenium 3.4.2
+
+* translate move_by_offset command to w3c
+* Update capabilities properly instead of assuming dict structure. Fixes #3927
+* Add missing file for Chrome options to API docs.
+* Add Chrome options module to API docs.
+
+Selenium 3.4.1
+* Add back the ability to set profile when using Firefox 45ESR. Fixes #3897
+
+Selenium 3.4.0
+* Correct usage of newSession around `firstMatch` and `alwaysMatch`
+* Remove superfluous capabilities that are not needed
+* Add expected condition that waits for all found elements to be visible (#3532)
+* Allow methods wrapped by EventFiringWebDriver and EventFiringWebElement (#806)
+* Dropping `javascriptEnabled` capability for real browsers
+* Use W3C check from parent object instead of assuming from capabilities
+* Bump example source distribution to match latest release.
+* Replace TypeError with KeyError in remote webdriver error handler code (#3826)
+* When testing Marionette use default capabilities in testing
+* Conform to the api of urllib2 for adding header for a request (#3803)
+* Add `text` key to alert#sendKeys parameters for W3C Endpoint
+* Location once scrolled into view should use W3C executeScript endpoint not JSONWP
+* Fixed the usage information in documentation of "save_screenshot". (#3804)
+* Add Element Not Interactable exception
+* Clean up imports in error handler
+* flake8 cleanup
+
+Selenium 3.3.3
+
+* make w3c execute_script commands unique
+
+Selenium 3.3.2
+
+* Update window commands to use W3C End points
+* Update Alert when in W3C mode to use W3C Endpoints
+* Update to new W3C Execute Script end points
+* Add setting/getting proxy details to Firefox Options
+* Deprecate the use of browser profile when instantiating a session
+* Update start session to handle the W3C New Session
+* Add get/set window rect commands
+* Add InvalidArgumentException
+* When passing in `text` to send_keys, make sure we send a string not array
+* Fix string decoding in remote connection (#3663)
+* Fix indentation to satisfy PEP8
+* Try use old way of setting page load timeout if new way fails. Fixes #3654
+* fix file uploads for Firefox
+* Run unit tests on Python 3.3, 3.4, and 3.5 (#3638)
+* Fix indentation in double_click.
+* Fix non-W3C page load timeout setting.
+
+Selenium 3.3.1
+* Fix encoding of basic auth header when using Python 3 Fixes #3622
+* Add initial unit test suite
+* Update W3C Timeout setting to be in line with the specification
+* support.ui.Select class inherits from object (#3067)
+* fix bug in proxy constructor that some properties are not proper set (#3459)
+* Fix flake8 issues (#3628)
+
+Selenium 3.3.0
+** Note ** If you are updating to this version, please also update GeckoDriver to v0.15.0
+* Fix python HTTPS encoding for python driver (#3379)
+* Allow Firefox preferences to be set directly in Options
+* Fix shutdown and process termination (#3263)
+* Preventing exception if log_path is none or empty. Fixes #3128
+* Add the W3C capability to Firefox for accepting insecure certificates
+* Initial implementation of Pointer Actions
+* Only skip tests if driver name matches a directory name.
+* Update calls that return a pure object with keys to look for 'value' key
+* Initial W3C Actions support
+* fix docs output directory
+
+Selenium 3.0.2
+* Add support for W3C Get Active Element
+* Return when we use executeScript for faking WebElement.get_property
+* Expand user paths and resolve absolute path for Chrome extensions
+* Add support for verbose logging and custom path to EdgeDriver
+* Update TakeElementScreenshot to match WebDriver specification
+* Raise WebDriverException when FirefoxBinary fails to locate binary
+* Fix getting IP for python 3
+* Write Service log to DEVNULL by default
+* Only attempt to remove the Firefox profile path if one was specified
+* Added context manager for chrome/content in Firefox
+
+Selenium 3.0.1
+* Fix regressions with python 3
+* Add support for Safari Technology Preview
+
+Selenium 3.0.0
+* new FirefoxDriver ctor precedence logic and moz:firefoxOptions support (#2882)
+* Add W3C Set Window Position and W3C Get Window Position
+* enable log path setting from firefox webdriver (#2700)
+* Correct encoding of getAttribute.js and only load it once. Fixes #2785
+* Encode the isDisplayed atom and only load it once
+
+Selenium 3.0.0.b3
+* Use atoms for get_attribute and is_displayed when communicating with
+  a w3c compliant remote end.
+* Make it possible to specialise web element
+
+Selenium 3.0.0.b2
+* Updated Marionette port argument to match other drivers.
+
+Selenium 3.0.0.b1
+* Fix basestring reference to work with python 3. Fixes #1820
+* Correct Length conditional when filtering in PhantomJS. Fixes #1817
+* Fix send keys when using PUA keys e.g. Keys.RIGHT #1839
+* Fix cookie file leak in PhantomJS #1854
+* Use the correct binary path when using Marionette
+* Fixed: Unhelpful error message when PhantomJS exits. (#2173 #2168)
+* Fix broken link to python documentation (#2159)
+* Attempt to remove Firefox profile when using Marionette
+* Ensure all capabilities are either within desiredCapabilities or requiredCapabilities
+* Correct the expected capability name for the Firefox profile
+* Add Firefox options to capabilities
+* Visibility_of_all implies it only returns elements if all visible (#2052)
+* Find visible elements (#2041)
+*  Pass the firefox_profile as a desired capability in the Python client when using a remote server
+* Avoid checking exception details for invalid locators due to differences in server implementations
+* Handle capabilities better with Marionette and GeckoDriver
+* Updated the maxVersion of FirefoxDriver xpi maxVersion to work with Firefox 47.0.1
+* Remove Selenium RC support
+
+Selenium 2.53.0
+* Adding Options object for use with Python FirefoxDriver
+* Fixed improper usage of super in exceptions module
+* create a temp file for cookies in phantomjs if not specified
+* Pass in the executable that FirefoxBinary finds to the service if there isnt one passed in as a kwarg or capability
+* Applied some DRY and extracted out the keys_to_typing()
+* Fix deselecting options in <select>
+
+
+Selenium 2.52.0
+* Fixing case where UnexpectedAlertException doesn't get the alert_text in the error object
+* Firefox: Actually use launch_browser timeout Fixes #1300
+
+Selenium 2.51.1
+* correcting bundling issue missing README.rst file
+
+Selenium 2.51.0
+* Firefox updates (see java changelog)
+
+Selenium 2.50.1
+* Fixing error message handling. Fixes issue #1497
+* Fixing error message handling. Fixes issue #1507
+* Update webelement to handle W3C commands for size/location and rect
+* rewrite click scrolling tests to match the Java ones
+
+Selenium 2.50.0
+* handle potential URLError from sending shutdown, set self.process to None after it's already been quit
+* Add support for submit() with W3C compliant endpoint
+
+Selenium 2.49.1
+* Ensure you can close stream before attempting to close it.
+* message response may cause json loads ValueError when it's not actually json
+  and just a string (like the message that occurs when firefox driver thinks
+  another element will receive the click)
+* Cleanup some error handling when sniffing what protocol you are speaking
+
+Selenium 2.49.0
+* Have Firefox service write to a file instead of PIPE
+* on osx for firefox, fallback to checking homebrew install, if the default isn't there
+* Added Firefox path variable for string placeholder
+* Update README to show Python 3.2+
+* refactoring all the service classes to use a common one.
+* Add Firefox specific command to switch context between Browser content and Browser chrome
+* updating files after go copyright:update
+* Use specificationLevel to know that we are speaking GeckoDriver
+* Bug fixes: #1294, #1186
+
+Selenium 2.48.0
+* Update error pulling to match spec when we encounter a spec compliant browser.
+* Disable tests that are not working with Marionette when running Marionette tests
+* Add the ability to run python marionette tests
+* Python 3 compatibility for remote Authorization
+* changing casing of children finding tests
+
+Selenium 2.47.3
+* Bring back py 3 support
+
+Selenium 2.47.2
+* Fix running Edge driver locally on win10
+* adding repr to WebDriver and WebElement
+
+Selenium 2.47.1
+* Fix the issue of deleting the profile when shutting down Firefox
+* WebElement __eq__ compares against more types
+* Issues fixed: 850
+
+Selenium 2.47.0
+* Add in support for when communicating with a Spec compliant browsers
+* Initial support for Edge using EdgeDriver
+* Issues fixed: 818
+
+Selenium 2.46.1
+* Adding ability to make remote call for webelement screenshots in accordance to the W3C spec
+* Adding api to authenticate HTTP Auth modal dialogs via driver.switch_to.alert (beta)
+* Add rebeccapurple to Color Object
+* Add element screenshot
+* Add service handler and minimal update to driver to use service for Marionette
+* Add the ability to start FirefoxDriver backed with Marionette via a capability
+* support socket timeout for connections
+* free_port checks if port is available on all interfaces
+* Allow error handling to handle both current errors and w3c errors
+* Update find_elements to match spec
+* phantomjs: service: remove unused import of signal
+* phantomjs: add port information to WebDriverException
+* Issues fixed (Github): 478, 612, 734, 780
+
+Selenium 2.46.0
+* Firefox support up to 38
+* BlackBerry browser support
+* remove Presto-Opera support
+* firefox extension extraction fixes
+* process management fixes with phantomjs
+* Comparing remote web element for equality does not require a remote command
+* Issues Fixed: (gcode) 8493, 8521, 8498, 8274, 8497, 5923
+* Issues Fixed: (github) 401
+
+Selenium 2.45.0
+* Firefox support up to 35, support for native events up to 34.
+* Make Opera driver support also the new Blink based Opera
+* README: Fix the Yahoo example
+* WebElement docstring fixes
+* Add debugger_address option to the ChromeDriver options list to optionally instruct ChromeDriver to wait for the target devtools instance to be started at a given host:ip
+* Set default value for PhantomJS process reference
+* Allow setting of FileDetector for send_keys
+* Pass info to TimeoutException in WebDriverWait
+* Issues Fixed: 8065, 8310, 8539
+
+Selenium 2.44.0
+* (previous release person forgot to add release notes! DAVID!)
+
+Selenium 2.43.0
+* Expand WebElement.get_attribute API docs
+* firefox may be installed without admininstrator privileges
+    and therefore there may be no HKEY_LOCAL_MACHINE entry. Issue #7784
+* UnexpectedAlertPresentException should contain the alert text in python too. Issue #7745
+* don't mutate the global 'ignored exceptions', take a copy of the globally specified ones, change the
+  global to be a tuple instead. Issue #7725
+* raise exception when the firefox binary isn't actually found, which usually implies the upgrade failed (on windows) Issue #6092 ,#6847
+* Fixing NameError: global name 'options' is not defined.
+* Remove unused import subprocess.PIPE
+* Redirect Firefox output to /dev/null by default Fixes Issue #7677
+* More flexible management of http timeouts in Selenium RC python client
+* Generate Python API docs for selenium.webdriver.chrome.options. Fixes issue #7471
+* Use 127.0.0.1 as localhost name resolving might fail on some systems
+
+Selenium 2.42.1
+* Fixed Py3 issues
+* Make firefox_binary.py and firefox_profile.py not executable
+* Make exceptions Python 3 compatible
+
+Selenium 2.42
+* Support for Firefox 29 Native Events
+* "remote_url" and "remote_browser" parameters for "./go test_remote".
+* missing __init__ in new android module
+* issue #7304 Fix memory leak caused by __del__ in PhantomJS
+* File upload using remotedriver on python3
+* Updating xpi install to align with mozprofile
+* command_executor should also support unicode strings as well.
+
+Selenium 2.41
+* Support for Firefox 28
+* deprecating switch_to_* in favour of driver.switch_to.*
+
+Selenium 2.40
+* Support for Firefox 27
+* Fixes related to http connection
+* Fix for phantomjs running on windows #6736
+
+Selenium 2.39
+* Support for Firefox 26
+
+Selenium 2.38.4
+* keep-alive can't be used for phantomjs / IE, fix for that and tested for py3 :)
+
+Selenium 2.38.3
+* really supporting py3 :)
+
+Selenium 2.38.2
+* py3 support (once again)
+
+Selenium 2.38.1
+* fix packaging problem where firefox/webdriver_prefs.json was missing
+
+Selenium 2.38
+* Support for Firefox 25
+* FirefoxProfile now using common webdriver.json instead of having our own copy in py
+  - behavior change to the preferences is that they now should be treated
+    like raw types rather than strings and allow the json library to translate
+    the types appropriated (e.g. True => true)
+
+* Set proper 'Accept' request header so that Python bindings work with some old WebDriver implementations that reply 404 to requests with no 'Accept' set.
+* handle redirect response explicitly (since switching to using keep-alive)
+* phantomjs service needs to really kill the spawned process Issue #5921
+* removing old api endpoints from command listing
+* using keep-alive for remote connection
+* adjusting phantomjs subprocess.Popen
+* ActionsChains.send_keys should use <session>/keys endpoint Issue #6348
+* fix TypeError in chrome_options.extensions for Python3.x
+
+* Other Bugs Fixed: #6531, #6513, #4569, #6454
+
+
+Selenium 2.37.2
+* fix regression added with unicode fix
+* Bug fix #6360
+
+Selenium 2.37.1
+* fix find_elements on webelement using unicode locators and py 2.7
+
+Selenium 2.37
+* repackage with fix for Firefox native events on Linux
+* fix issue with unicode By locators w/ python 2.7 #6430
+
+Selenium 2.36
+* Added Safari WebDriver. Fixes issue 5352.
+* fix platform for safari caps
+* Convert all offsets/coordinates/speeds into integers
+* Fix drag and drop by offset behaviour
+* Fix initialization of Proxy by capabilities when proxyType is set
+* Enable SOCKS proxy support
+* Validation of passed locator for find_element(s) methods #5690
+* Adding support for /status, /sessions commands
+* Doc fixes
+* ability to set Chrome extensions by using base64 encoded strings #4013
+* fix logic regarding Select.select_by_visible_text #3910
+* Bugs fixed: #6165, #6231
+
+Selenium 2.35
+* Remove duplicate 'get screenshot as file' methods.  Add method 'get_screenshot_as_png'
+* fixing UnicodeEncodeError on get attribute of webelement
+
+Selenium 2.34
+* Corrected webdriverbackedselenium session handling. Fixes issue 4283
+* Corrected use of basestring for python 3. Fixes issue 5924
+* Support for Firefox 22
+* Added support for logging from the browser
+* corrected proxy handling on FirefoxProfile
+* Corrected handling of chrome extensions. Fixes issue 5762
+
+Selenium 2.33
+* getText() ignores elements in the <head>
+* Adding both official and informal string representations to Color object.
+* Replace distutils.dir_util by shutil
+* Allow finding firefox binary at ProgramFiles(x86) on windows(64 bit)
+* Py3 compatible winreg import and content-type access
+
+Selenium 2.32
+* Support for FF20 Native Events
+* Python 3 support
+* Misc Python 3 patches
+* Allow easy FirefoxBinary subclassing
+
+Selenium 2.31
+* Support for FF19 native events
+* web element equality is now in conformance with other language bindings
+
+Selenium 2.30
+* Allow env to be specified for the chromedriver service
+* Allow log path to be specified for phantomjs driver service.
+* Bug Fixes: 4608 4940 4974 5034 5075
+
+Selenium 2.29
+* Allow subclassing of driver and have the ability to send_keys Issue 4877, 5017
+* Simplifying save_screenshot and allow phantomjs to take screenshots
+
+Selenium 2.28
+* "null" can now be passed to executeScript
+* Add transparent and extended colour keywords to color support module. Fixes issue 4866
+
+Selenium 2.27
+* Added support for phantomjs / ghostdriver
+* Fix python client, avoid duplicate chrome option items after reusing options class. Fixes Issue 4744.
+* adding colour support to Python. fixes issue 4623
+* Adding log_path/service_log_path as named kwargs for chrome
+
+Selenium 2.26
+* Added location_when_scrolled_into_view - Bug 4357
+* Added new expected_conditions support module to be used with WebDriverWait
+
+Selenium 2.25
+* Jython 2.7 Support - Bug 3988
+* EventFiringWebDriver added to Support module - Bug 2267
+* Added IEDriverServer logging that can be accessed via desired capabilities
+* Fixed by data being passed into find_elements - bug 3735
+* Removed deprecated ChromeDriver items around desiredcapabilites in favour of chrome options
+* Added default values for a number of action_chains calls
+
+Selenium 2.24
+* Removing the ctypes approach of invoking IEDriver, you will need to download the IEDriverServer from
+  https://code.google.com/p/selenium/downloads/list
+
+Selenium 2.23
+* Support for FF13 native events
+
+Selenium 2.22
+* Moving IEDriver to be able to use IEDriverServer
+
+Selenium 2.21.3
+* Fix for File Upload to remote servers
+* Better handling of typing in input=file. Bug 3831, 3736
+* Better handling of unicode URLS Bug 3740
+
+Selenium 2.21.2
+* Fix typing to file input when not using Selenium Server. Bug 3736
+
+Selenium 2.21.1
+* focusmanager.testmode messes with native events, removing it.
+
+Selenium 2.21
+* Local File upload capabilities for non-remote browser
+* Adding maximize_window api call
+* Updating default firefox profile to set focusmanager.testmode to true
+    see https://bugzilla.mozilla.org/show_bug.cgi?id=704583
+* bugs fixed: 3506, 3528, 3607
+
+Selenium 2.20
+* disable native events for FF on Mac by default
+* fix webdriverwait to execute at least once when using 0 timeout
+* Fixed Issue 3438
+
+Selenium 2.19
+* WebDriverBackedSelenium is now avalaible to all languages
+* Addon installation fixes
+
+Selenium 2.18
+* Proxy capabilities passing
+
+Selenium 2.17
+* OperaDriver can now be invoked by webdriver.Opera()
+* Support has been added for ChomeOptions. This deprecates support passing in DesiredCapabilities
+* Proxy class to tell the browser a proxy is in use. Currently only for Firefox
+
+Selenium 2.16
+* bug fixes
+
+Selenium 2.15
+* bug fixes
+
+Selenium 2.14
+* Fix for LD_PRELOAD being polluted by WebDriver
+* Added Orientation API
+* A fix for Error Handling
+
+Selenium 2.13
+* Fixed switch_to_window so that it didnt crash Firefox Bug 2633
+* Fixed Screenshot handling to work in all browsers. Bug 2829
+* Force Firefox to the Foreground
+
+Selenium 2.12
+* Added Select as a support pacakge
+* Added Beta window size / position api's
+* Bug Fixes
+
+Selenium 2.11.0 2.11.1
+* no changes just packaging
+
+Selenum 2.10
+* "Choose which apps" dialog has been disabled
+* Bug Fixes
+
+Selenium 2.9
+* Bug Fixes
+* Documentation
+
+Selenium 2.8
+* Actions updates
+* Bug Fixes
+
+Selenium 2.6
+* Documentation fixes
+
+Selenium 2.5
+* Fixed x64 IE Support
+* Bug Fixes
+
+Selenium 2.4
+* Bug Fixes
+* x64 IE Support
+* Added WebDriverWait as a support package
+
+Selenium 2.3
+* Bug Fixes
+
+Selenium 2.2
+* Ability to get screenshots from Exceptions if they are given
+* Access to Remote StackTrace on error
+
+Selenium 2.1
+* Bug Fixes
+
+Selenium 2
+* Removed toggle() and select()
+
+Selenium 2 RC 3
+* Added Opera to Desired Capabilities
+* Removed deprecrated methods
+* Deprecated toggle() and select() methods. This will be removed in the next release
+
+Selenium 2 Beta 4
+* Fix for using existing Firefox Profiles
+* Alerts Support in IE
+* Fix to dictionary returned from size
+* Deprecated value property. Use the get_attribute("value") method
+* Deprecated get_page_source method. Use page_source property
+* Deprecated get_current_window_handle. Use current_window_handle property
+* Deprecated get_window_handles. Use window_handles property
+* Ability to install extensions into profiles
+* Added Location to the WebElement
+* ChromeDriver rewritten to use new built in mechanism
+* Added Advanced User Interaction API. Only Available for HTMLUnit at the moment
+* Profiles now delete their temp folders when driver.quit() is called
+
+Selenium 2 Beta 3
+* Accept Untrusted Certificates in Firefox
+* Fixed Screenshots
+* Added DesiredCapabilities to simplify choosing Drivers
+* Fixed Firefox Profile creation
+* Added Firefox 4 support
+* DocStrings Improvements
+
+Selenium 2 Beta 2
+
+* New bindings landed. Change webdriver namespace to "selenium.webdriver"
+* Ability to move to default content
+* Implicit Waits
+* Change the API to use properties instead of get_x
+* Changed the Element Finding to match other languages
+* Added ability to execute asynchronous scripts from the driver
+* Ability to get rendered element size
+* Ability to get CSS Value on a webelement
+* Corrected Element finding from the element
+* Alert and Prompt handling
+* Improved IEDriver
+* Basic Authentication support for Selenium 2
+* Ability to have multiple Firefox instances

+ 202 - 0
selenium-3.141.0/LICENSE

@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2018 Software Freedom Conservancy (SFC)
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 22 - 0
selenium-3.141.0/MANIFEST.in

@@ -0,0 +1,22 @@
+prune *
+recursive-include selenium/webdriver *.py
+recursive-include selenium/webdriver/common *.py
+recursive-include selenium/webdriver/common/actions *.py
+recursive-include selenium/webdriver/common/html5 *.py
+recursive-include selenium/common *.py
+recursive-include selenium/webdriver/chrome *.py
+recursive-include selenium/webdriver/opera *.py
+recursive-include selenium/webdriver/phantomjs *.py
+recursive-include selenium/webdriver/firefox *.py *.xpi *.json
+recursive-include selenium/webdriver/firefox/x86 *.so
+recursive-include selenium/webdriver/firefox/amd64 *.so
+recursive-include selenium/webdriver/ie *.py
+recursive-include selenium/webdriver/edge *.py
+recursive-include selenium/webdriver/remote *.py *.js
+recursive-include selenium/webdriver/support *.py
+include selenium/selenium.py
+include selenium/__init__.py
+include CHANGES
+include README.rst
+include LICENSE
+recursive-include selenium.egg-info *

+ 168 - 0
selenium-3.141.0/PKG-INFO

@@ -0,0 +1,168 @@
+Metadata-Version: 1.1
+Name: selenium
+Version: 3.141.0
+Summary: Python bindings for Selenium
+Home-page: https://github.com/SeleniumHQ/selenium/
+Author: UNKNOWN
+Author-email: UNKNOWN
+License: Apache 2.0
+Description: ======================
+        Selenium Client Driver
+        ======================
+        
+        Introduction
+        ============
+        
+        Python language bindings for Selenium WebDriver.
+        
+        The `selenium` package is used to automate web browser interaction from Python.
+        
+        +-----------+--------------------------------------------------------------------------------------+
+        | **Home**: | http://www.seleniumhq.org                                                            |
+        +-----------+--------------------------------------------------------------------------------------+
+        | **Docs**: | `selenium package API <https://seleniumhq.github.io/selenium/docs/api/py/api.html>`_ |
+        +-----------+--------------------------------------------------------------------------------------+
+        | **Dev**:  | https://github.com/SeleniumHQ/Selenium                                               |
+        +-----------+--------------------------------------------------------------------------------------+
+        | **PyPI**: | https://pypi.org/project/selenium/                                                   |
+        +-----------+--------------------------------------------------------------------------------------+
+        | **IRC**:  | **#selenium** channel on freenode                                                    |
+        +-----------+--------------------------------------------------------------------------------------+
+        
+        Several browsers/drivers are supported (Firefox, Chrome, Internet Explorer), as well as the Remote protocol.
+        
+        Supported Python Versions
+        =========================
+        
+        * Python 2.7, 3.4+
+        
+        Installing
+        ==========
+        
+        If you have `pip <https://pip.pypa.io/>`_ on your system, you can simply install or upgrade the Python bindings::
+        
+            pip install -U selenium
+        
+        Alternately, you can download the source distribution from `PyPI <https://pypi.org/project/selenium/#files>`_ (e.g. selenium-3.141.0.tar.gz), unarchive it, and run::
+        
+            python setup.py install
+        
+        Note: You may want to consider using `virtualenv <http://www.virtualenv.org/>`_ to create isolated Python environments.
+        
+        Drivers
+        =======
+        
+        Selenium requires a driver to interface with the chosen browser. Firefox,
+        for example, requires `geckodriver <https://github.com/mozilla/geckodriver/releases>`_, which needs to be installed before the below examples can be run. Make sure it's in your `PATH`, e. g., place it in `/usr/bin` or `/usr/local/bin`.
+        
+        Failure to observe this step will give you an error `selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs to be in PATH.`
+        
+        Other supported browsers will have their own drivers available. Links to some of the more popular browser drivers follow.
+        
+        +--------------+-----------------------------------------------------------------------+
+        | **Chrome**:  | https://sites.google.com/a/chromium.org/chromedriver/downloads        |
+        +--------------+-----------------------------------------------------------------------+
+        | **Edge**:    | https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ |
+        +--------------+-----------------------------------------------------------------------+
+        | **Firefox**: | https://github.com/mozilla/geckodriver/releases                       |
+        +--------------+-----------------------------------------------------------------------+
+        | **Safari**:  | https://webkit.org/blog/6900/webdriver-support-in-safari-10/          |
+        +--------------+-----------------------------------------------------------------------+
+        
+        Example 0:
+        ==========
+        
+        * open a new Firefox browser
+        * load the page at the given URL
+        
+        .. code-block:: python
+        
+            from selenium import webdriver
+        
+            browser = webdriver.Firefox()
+            browser.get('http://seleniumhq.org/')
+        
+        Example 1:
+        ==========
+        
+        * open a new Firefox browser
+        * load the Yahoo homepage
+        * search for "seleniumhq"
+        * close the browser
+        
+        .. code-block:: python
+        
+            from selenium import webdriver
+            from selenium.webdriver.common.keys import Keys
+        
+            browser = webdriver.Firefox()
+        
+            browser.get('http://www.yahoo.com')
+            assert 'Yahoo' in browser.title
+        
+            elem = browser.find_element_by_name('p')  # Find the search box
+            elem.send_keys('seleniumhq' + Keys.RETURN)
+        
+            browser.quit()
+        
+        Example 2:
+        ==========
+        
+        Selenium WebDriver is often used as a basis for testing web applications.  Here is a simple example using Python's standard `unittest <http://docs.python.org/3/library/unittest.html>`_ library:
+        
+        .. code-block:: python
+        
+            import unittest
+            from selenium import webdriver
+        
+            class GoogleTestCase(unittest.TestCase):
+        
+                def setUp(self):
+                    self.browser = webdriver.Firefox()
+                    self.addCleanup(self.browser.quit)
+        
+                def testPageTitle(self):
+                    self.browser.get('http://www.google.com')
+                    self.assertIn('Google', self.browser.title)
+        
+            if __name__ == '__main__':
+                unittest.main(verbosity=2)
+        
+        Selenium Server (optional)
+        ==========================
+        
+        For normal WebDriver scripts (non-Remote), the Java server is not needed.
+        
+        However, to use Selenium Webdriver Remote or the legacy Selenium API (Selenium-RC), you need to also run the Selenium server.  The server requires a Java Runtime Environment (JRE).
+        
+        Download the server separately, from: http://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.0.jar
+        
+        Run the server from the command line::
+        
+            java -jar selenium-server-standalone-3.141.0.jar
+        
+        Then run your Python client scripts.
+        
+        Use The Source Luke!
+        ====================
+        
+        View source code online:
+        
+        +-----------+-------------------------------------------------------+
+        | official: | https://github.com/SeleniumHQ/selenium/tree/master/py |
+        +-----------+-------------------------------------------------------+
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: POSIX
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Topic :: Software Development :: Testing
+Classifier: Topic :: Software Development :: Libraries
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6

+ 145 - 0
selenium-3.141.0/README.rst

@@ -0,0 +1,145 @@
+======================
+Selenium Client Driver
+======================
+
+Introduction
+============
+
+Python language bindings for Selenium WebDriver.
+
+The `selenium` package is used to automate web browser interaction from Python.
+
++-----------+--------------------------------------------------------------------------------------+
+| **Home**: | http://www.seleniumhq.org                                                            |
++-----------+--------------------------------------------------------------------------------------+
+| **Docs**: | `selenium package API <https://seleniumhq.github.io/selenium/docs/api/py/api.html>`_ |
++-----------+--------------------------------------------------------------------------------------+
+| **Dev**:  | https://github.com/SeleniumHQ/Selenium                                               |
++-----------+--------------------------------------------------------------------------------------+
+| **PyPI**: | https://pypi.org/project/selenium/                                                   |
++-----------+--------------------------------------------------------------------------------------+
+| **IRC**:  | **#selenium** channel on freenode                                                    |
++-----------+--------------------------------------------------------------------------------------+
+
+Several browsers/drivers are supported (Firefox, Chrome, Internet Explorer), as well as the Remote protocol.
+
+Supported Python Versions
+=========================
+
+* Python 2.7, 3.4+
+
+Installing
+==========
+
+If you have `pip <https://pip.pypa.io/>`_ on your system, you can simply install or upgrade the Python bindings::
+
+    pip install -U selenium
+
+Alternately, you can download the source distribution from `PyPI <https://pypi.org/project/selenium/#files>`_ (e.g. selenium-3.141.0.tar.gz), unarchive it, and run::
+
+    python setup.py install
+
+Note: You may want to consider using `virtualenv <http://www.virtualenv.org/>`_ to create isolated Python environments.
+
+Drivers
+=======
+
+Selenium requires a driver to interface with the chosen browser. Firefox,
+for example, requires `geckodriver <https://github.com/mozilla/geckodriver/releases>`_, which needs to be installed before the below examples can be run. Make sure it's in your `PATH`, e. g., place it in `/usr/bin` or `/usr/local/bin`.
+
+Failure to observe this step will give you an error `selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs to be in PATH.`
+
+Other supported browsers will have their own drivers available. Links to some of the more popular browser drivers follow.
+
++--------------+-----------------------------------------------------------------------+
+| **Chrome**:  | https://sites.google.com/a/chromium.org/chromedriver/downloads        |
++--------------+-----------------------------------------------------------------------+
+| **Edge**:    | https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ |
++--------------+-----------------------------------------------------------------------+
+| **Firefox**: | https://github.com/mozilla/geckodriver/releases                       |
++--------------+-----------------------------------------------------------------------+
+| **Safari**:  | https://webkit.org/blog/6900/webdriver-support-in-safari-10/          |
++--------------+-----------------------------------------------------------------------+
+
+Example 0:
+==========
+
+* open a new Firefox browser
+* load the page at the given URL
+
+.. code-block:: python
+
+    from selenium import webdriver
+
+    browser = webdriver.Firefox()
+    browser.get('http://seleniumhq.org/')
+
+Example 1:
+==========
+
+* open a new Firefox browser
+* load the Yahoo homepage
+* search for "seleniumhq"
+* close the browser
+
+.. code-block:: python
+
+    from selenium import webdriver
+    from selenium.webdriver.common.keys import Keys
+
+    browser = webdriver.Firefox()
+
+    browser.get('http://www.yahoo.com')
+    assert 'Yahoo' in browser.title
+
+    elem = browser.find_element_by_name('p')  # Find the search box
+    elem.send_keys('seleniumhq' + Keys.RETURN)
+
+    browser.quit()
+
+Example 2:
+==========
+
+Selenium WebDriver is often used as a basis for testing web applications.  Here is a simple example using Python's standard `unittest <http://docs.python.org/3/library/unittest.html>`_ library:
+
+.. code-block:: python
+
+    import unittest
+    from selenium import webdriver
+
+    class GoogleTestCase(unittest.TestCase):
+
+        def setUp(self):
+            self.browser = webdriver.Firefox()
+            self.addCleanup(self.browser.quit)
+
+        def testPageTitle(self):
+            self.browser.get('http://www.google.com')
+            self.assertIn('Google', self.browser.title)
+
+    if __name__ == '__main__':
+        unittest.main(verbosity=2)
+
+Selenium Server (optional)
+==========================
+
+For normal WebDriver scripts (non-Remote), the Java server is not needed.
+
+However, to use Selenium Webdriver Remote or the legacy Selenium API (Selenium-RC), you need to also run the Selenium server.  The server requires a Java Runtime Environment (JRE).
+
+Download the server separately, from: http://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.0.jar
+
+Run the server from the command line::
+
+    java -jar selenium-server-standalone-3.141.0.jar
+
+Then run your Python client scripts.
+
+Use The Source Luke!
+====================
+
+View source code online:
+
++-----------+-------------------------------------------------------+
+| official: | https://github.com/SeleniumHQ/selenium/tree/master/py |
++-----------+-------------------------------------------------------+

+ 19 - 0
selenium-3.141.0/build/lib/selenium/__init__.py

@@ -0,0 +1,19 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+__version__ = "3.141.0"

+ 18 - 0
selenium-3.141.0/build/lib/selenium/common/__init__.py

@@ -0,0 +1,18 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from . import exceptions  # noqa

+ 327 - 0
selenium-3.141.0/build/lib/selenium/common/exceptions.py

@@ -0,0 +1,327 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Exceptions that may happen in all the webdriver code.
+"""
+
+
+class WebDriverException(Exception):
+    """
+    Base webdriver exception.
+    """
+
+    def __init__(self, msg=None, screen=None, stacktrace=None):
+        self.msg = msg
+        self.screen = screen
+        self.stacktrace = stacktrace
+
+    def __str__(self):
+        exception_msg = "Message: %s\n" % self.msg
+        if self.screen is not None:
+            exception_msg += "Screenshot: available via screen\n"
+        if self.stacktrace is not None:
+            stacktrace = "\n".join(self.stacktrace)
+            exception_msg += "Stacktrace:\n%s" % stacktrace
+        return exception_msg
+
+
+class ErrorInResponseException(WebDriverException):
+    """
+    Thrown when an error has occurred on the server side.
+
+    This may happen when communicating with the firefox extension
+    or the remote driver server.
+    """
+    def __init__(self, response, msg):
+        WebDriverException.__init__(self, msg)
+        self.response = response
+
+
+class InvalidSwitchToTargetException(WebDriverException):
+    """
+    Thrown when frame or window target to be switched doesn't exist.
+    """
+    pass
+
+
+class NoSuchFrameException(InvalidSwitchToTargetException):
+    """
+    Thrown when frame target to be switched doesn't exist.
+    """
+    pass
+
+
+class NoSuchWindowException(InvalidSwitchToTargetException):
+    """
+    Thrown when window target to be switched doesn't exist.
+
+    To find the current set of active window handles, you can get a list
+    of the active window handles in the following way::
+
+        print driver.window_handles
+
+    """
+    pass
+
+
+class NoSuchElementException(WebDriverException):
+    """
+    Thrown when element could not be found.
+
+    If you encounter this exception, you may want to check the following:
+        * Check your selector used in your find_by...
+        * Element may not yet be on the screen at the time of the find operation,
+          (webpage is still loading) see selenium.webdriver.support.wait.WebDriverWait()
+          for how to write a wait wrapper to wait for an element to appear.
+    """
+    pass
+
+
+class NoSuchAttributeException(WebDriverException):
+    """
+    Thrown when the attribute of element could not be found.
+
+    You may want to check if the attribute exists in the particular browser you are
+    testing against.  Some browsers may have different property names for the same
+    property.  (IE8's .innerText vs. Firefox .textContent)
+    """
+    pass
+
+
+class StaleElementReferenceException(WebDriverException):
+    """
+    Thrown when a reference to an element is now "stale".
+
+    Stale means the element no longer appears on the DOM of the page.
+
+
+    Possible causes of StaleElementReferenceException include, but not limited to:
+        * You are no longer on the same page, or the page may have refreshed since the element
+          was located.
+        * The element may have been removed and re-added to the screen, since it was located.
+          Such as an element being relocated.
+          This can happen typically with a javascript framework when values are updated and the
+          node is rebuilt.
+        * Element may have been inside an iframe or another context which was refreshed.
+    """
+    pass
+
+
+class InvalidElementStateException(WebDriverException):
+    """
+    Thrown when a command could not be completed because the element is in an invalid state.
+
+    This can be caused by attempting to clear an element that isn't both editable and resettable.
+    """
+    pass
+
+
+class UnexpectedAlertPresentException(WebDriverException):
+    """
+    Thrown when an unexpected alert is appeared.
+
+    Usually raised when when an expected modal is blocking webdriver form executing any
+    more commands.
+    """
+    def __init__(self, msg=None, screen=None, stacktrace=None, alert_text=None):
+        super(UnexpectedAlertPresentException, self).__init__(msg, screen, stacktrace)
+        self.alert_text = alert_text
+
+    def __str__(self):
+        return "Alert Text: %s\n%s" % (self.alert_text, super(UnexpectedAlertPresentException, self).__str__())
+
+
+class NoAlertPresentException(WebDriverException):
+    """
+    Thrown when switching to no presented alert.
+
+    This can be caused by calling an operation on the Alert() class when an alert is
+    not yet on the screen.
+    """
+    pass
+
+
+class ElementNotVisibleException(InvalidElementStateException):
+    """
+    Thrown when an element is present on the DOM, but
+    it is not visible, and so is not able to be interacted with.
+
+    Most commonly encountered when trying to click or read text
+    of an element that is hidden from view.
+    """
+    pass
+
+
+class ElementNotInteractableException(InvalidElementStateException):
+    """
+    Thrown when an element is present in the DOM but interactions
+    with that element will hit another element do to paint order
+    """
+    pass
+
+
+class ElementNotSelectableException(InvalidElementStateException):
+    """
+    Thrown when trying to select an unselectable element.
+
+    For example, selecting a 'script' element.
+    """
+    pass
+
+
+class InvalidCookieDomainException(WebDriverException):
+    """
+    Thrown when attempting to add a cookie under a different domain
+    than the current URL.
+    """
+    pass
+
+
+class UnableToSetCookieException(WebDriverException):
+    """
+    Thrown when a driver fails to set a cookie.
+    """
+    pass
+
+
+class RemoteDriverServerException(WebDriverException):
+    """
+    """
+    pass
+
+
+class TimeoutException(WebDriverException):
+    """
+    Thrown when a command does not complete in enough time.
+    """
+    pass
+
+
+class MoveTargetOutOfBoundsException(WebDriverException):
+    """
+    Thrown when the target provided to the `ActionsChains` move()
+    method is invalid, i.e. out of document.
+    """
+    pass
+
+
+class UnexpectedTagNameException(WebDriverException):
+    """
+    Thrown when a support class did not get an expected web element.
+    """
+    pass
+
+
+class InvalidSelectorException(NoSuchElementException):
+    """
+    Thrown when the selector which is used to find an element does not return
+    a WebElement. Currently this only happens when the selector is an xpath
+    expression and it is either syntactically invalid (i.e. it is not a
+    xpath expression) or the expression does not select WebElements
+    (e.g. "count(//input)").
+    """
+    pass
+
+
+class ImeNotAvailableException(WebDriverException):
+    """
+    Thrown when IME support is not available. This exception is thrown for every IME-related
+    method call if IME support is not available on the machine.
+    """
+    pass
+
+
+class ImeActivationFailedException(WebDriverException):
+    """
+    Thrown when activating an IME engine has failed.
+    """
+    pass
+
+
+class InvalidArgumentException(WebDriverException):
+    """
+    The arguments passed to a command are either invalid or malformed.
+    """
+    pass
+
+
+class JavascriptException(WebDriverException):
+    """
+    An error occurred while executing JavaScript supplied by the user.
+    """
+    pass
+
+
+class NoSuchCookieException(WebDriverException):
+    """
+    No cookie matching the given path name was found amongst the associated cookies of the
+    current browsing context's active document.
+    """
+    pass
+
+
+class ScreenshotException(WebDriverException):
+    """
+    A screen capture was made impossible.
+    """
+    pass
+
+
+class ElementClickInterceptedException(WebDriverException):
+    """
+    The Element Click command could not be completed because the element receiving the events
+    is obscuring the element that was requested clicked.
+    """
+    pass
+
+
+class InsecureCertificateException(WebDriverException):
+    """
+    Navigation caused the user agent to hit a certificate warning, which is usually the result
+    of an expired or invalid TLS certificate.
+    """
+    pass
+
+
+class InvalidCoordinatesException(WebDriverException):
+    """
+    The coordinates provided to an interactions operation are invalid.
+    """
+    pass
+
+
+class InvalidSessionIdException(WebDriverException):
+    """
+    Occurs if the given session id is not in the list of active sessions, meaning the session
+    either does not exist or that it's not active.
+    """
+    pass
+
+
+class SessionNotCreatedException(WebDriverException):
+    """
+    A new session could not be created.
+    """
+    pass
+
+
+class UnknownMethodException(WebDriverException):
+    """
+    The requested command matched a known URL but did not match an method for that URL.
+    """
+    pass

+ 39 - 0
selenium-3.141.0/build/lib/selenium/webdriver/__init__.py

@@ -0,0 +1,39 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from .firefox.webdriver import WebDriver as Firefox  # noqa
+from .firefox.firefox_profile import FirefoxProfile  # noqa
+from .firefox.options import Options as FirefoxOptions  # noqa
+from .chrome.webdriver import WebDriver as Chrome  # noqa
+from .chrome.options import Options as ChromeOptions  # noqa
+from .ie.webdriver import WebDriver as Ie  # noqa
+from .ie.options import Options as IeOptions  # noqa
+from .edge.webdriver import WebDriver as Edge  # noqa
+from .opera.webdriver import WebDriver as Opera  # noqa
+from .safari.webdriver import WebDriver as Safari  # noqa
+from .blackberry.webdriver import WebDriver as BlackBerry  # noqa
+from .phantomjs.webdriver import WebDriver as PhantomJS  # noqa
+from .android.webdriver import WebDriver as Android  # noqa
+from .webkitgtk.webdriver import WebDriver as WebKitGTK # noqa
+from .webkitgtk.options import Options as WebKitGTKOptions # noqa
+from .remote.webdriver import WebDriver as Remote  # noqa
+from .common.desired_capabilities import DesiredCapabilities  # noqa
+from .common.action_chains import ActionChains  # noqa
+from .common.touch_actions import TouchActions  # noqa
+from .common.proxy import Proxy  # noqa
+
+__version__ = '3.14.1'

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/android/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 42 - 0
selenium-3.141.0/build/lib/selenium/webdriver/android/webdriver.py

@@ -0,0 +1,42 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+
+
+class WebDriver(RemoteWebDriver):
+    """
+    Simple RemoteWebDriver wrapper to start connect to Selendroid's WebView app
+
+    For more info on getting started with Selendroid
+    http://selendroid.io/mobileWeb.html
+    """
+
+    def __init__(self, host="localhost", port=4444, desired_capabilities=DesiredCapabilities.ANDROID):
+        """
+        Creates a new instance of Selendroid using the WebView app
+
+        :Args:
+         - host - location of where selendroid is running
+         - port - port that selendroid is running on
+         - desired_capabilities: Dictionary object with capabilities
+        """
+        RemoteWebDriver.__init__(
+            self,
+            command_executor="http://%s:%d/wd/hub" % (host, port),
+            desired_capabilities=desired_capabilities)

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/blackberry/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 116 - 0
selenium-3.141.0/build/lib/selenium/webdriver/blackberry/webdriver.py

@@ -0,0 +1,116 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import os
+import platform
+import subprocess
+
+try:
+    import http.client as http_client
+except ImportError:
+    import httplib as http_client
+
+from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
+from selenium.common.exceptions import WebDriverException
+from selenium.webdriver.support.ui import WebDriverWait
+
+LOAD_TIMEOUT = 5
+
+
+class WebDriver(RemoteWebDriver):
+    """
+    Controls the BlackBerry Browser and allows you to drive it.
+
+    :Args:
+     - device_password - password for the BlackBerry device or emulator you are
+       trying to drive
+     - bb_tools_dir path to the blackberry-deploy executable. If the default
+       is used it assumes it is in the $PATH
+     - hostip - the ip for the device you are trying to drive. Falls back to
+       169.254.0.1 which is the default ip used
+     - port - the port being used for WebDriver on device. defaults to 1338
+     - desired_capabilities: Dictionary object with non-browser specific
+       capabilities only, such as "proxy" or "loggingPref".
+
+    Note: To get blackberry-deploy you will need to install the BlackBerry
+          WebWorks SDK - the default install will put it in the $PATH for you.
+          Download at https://developer.blackberry.com/html5/downloads/
+    """
+    def __init__(self, device_password, bb_tools_dir=None,
+                 hostip='169.254.0.1', port=1338, desired_capabilities={}):
+        remote_addr = 'http://{}:{}'.format(hostip, port)
+
+        filename = 'blackberry-deploy'
+        if platform.system() == "Windows":
+            filename += '.bat'
+
+        if bb_tools_dir is not None:
+            if os.path.isdir(bb_tools_dir):
+                bb_deploy_location = os.path.join(bb_tools_dir, filename)
+                if not os.path.isfile(bb_deploy_location):
+                    raise WebDriverException('Invalid blackberry-deploy location: {}'.format(bb_deploy_location))
+            else:
+                raise WebDriverException('Invalid blackberry tools location, must be a directory: {}'.format(bb_tools_dir))
+        else:
+            bb_deploy_location = filename
+
+        """
+        Now launch the BlackBerry browser before allowing anything else to run.
+        """
+        try:
+            launch_args = [bb_deploy_location,
+                           '-launchApp',
+                           str(hostip),
+                           '-package-name', 'sys.browser',
+                           '-package-id', 'gYABgJYFHAzbeFMPCCpYWBtHAm0',
+                           '-password', str(device_password)]
+
+            with open(os.devnull, 'w') as fp:
+                p = subprocess.Popen(launch_args, stdout=fp)
+
+            returncode = p.wait()
+
+            if returncode == 0:
+                # wait for the BlackBerry10 browser to load.
+                is_running_args = [bb_deploy_location,
+                                   '-isAppRunning',
+                                   str(hostip),
+                                   '-package-name', 'sys.browser',
+                                   '-package-id', 'gYABgJYFHAzbeFMPCCpYWBtHAm0',
+                                   '-password', str(device_password)]
+
+                WebDriverWait(None, LOAD_TIMEOUT)\
+                    .until(lambda x: subprocess.check_output(is_running_args)
+                           .find('result::true'),
+                           message='waiting for BlackBerry10 browser to load')
+
+                RemoteWebDriver.__init__(self,
+                                         command_executor=remote_addr,
+                                         desired_capabilities=desired_capabilities)
+            else:
+                raise WebDriverException('blackberry-deploy failed to launch browser')
+        except Exception as e:
+            raise WebDriverException('Something went wrong launching blackberry-deploy', stacktrace=getattr(e, 'stacktrace', None))
+
+    def quit(self):
+        """
+        Closes the browser and shuts down the
+        """
+        try:
+            RemoteWebDriver.quit(self)
+        except http_client.BadStatusLine:
+            pass

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/chrome/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 211 - 0
selenium-3.141.0/build/lib/selenium/webdriver/chrome/options.py

@@ -0,0 +1,211 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import base64
+import os
+import platform
+import warnings
+
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+
+
+class Options(object):
+    KEY = "goog:chromeOptions"
+
+    def __init__(self):
+        self._binary_location = ''
+        self._arguments = []
+        self._extension_files = []
+        self._extensions = []
+        self._experimental_options = {}
+        self._debugger_address = None
+        self._caps = DesiredCapabilities.CHROME.copy()
+
+    @property
+    def binary_location(self):
+        """
+        Returns the location of the binary otherwise an empty string
+        """
+        return self._binary_location
+
+    @binary_location.setter
+    def binary_location(self, value):
+        """
+        Allows you to set where the chromium binary lives
+
+        :Args:
+         - value: path to the Chromium binary
+        """
+        self._binary_location = value
+
+    @property
+    def capabilities(self):
+        return self._caps
+
+    def set_capability(self, name, value):
+        """Sets a capability."""
+        self._caps[name] = value
+
+    @property
+    def debugger_address(self):
+        """
+        Returns the address of the remote devtools instance
+        """
+        return self._debugger_address
+
+    @debugger_address.setter
+    def debugger_address(self, value):
+        """
+        Allows you to set the address of the remote devtools instance
+        that the ChromeDriver instance will try to connect to during an
+        active wait.
+
+        :Args:
+         - value: address of remote devtools instance if any (hostname[:port])
+        """
+        self._debugger_address = value
+
+    @property
+    def arguments(self):
+        """
+        Returns a list of arguments needed for the browser
+        """
+        return self._arguments
+
+    def add_argument(self, argument):
+        """
+        Adds an argument to the list
+
+        :Args:
+         - Sets the arguments
+        """
+        if argument:
+            self._arguments.append(argument)
+        else:
+            raise ValueError("argument can not be null")
+
+    @property
+    def extensions(self):
+        """
+        Returns a list of encoded extensions that will be loaded into chrome
+
+        """
+        encoded_extensions = []
+        for ext in self._extension_files:
+            file_ = open(ext, 'rb')
+            # Should not use base64.encodestring() which inserts newlines every
+            # 76 characters (per RFC 1521).  Chromedriver has to remove those
+            # unnecessary newlines before decoding, causing performance hit.
+            encoded_extensions.append(base64.b64encode(file_.read()).decode('UTF-8'))
+
+            file_.close()
+        return encoded_extensions + self._extensions
+
+    def add_extension(self, extension):
+        """
+        Adds the path to the extension to a list that will be used to extract it
+        to the ChromeDriver
+
+        :Args:
+         - extension: path to the \*.crx file
+        """
+        if extension:
+            extension_to_add = os.path.abspath(os.path.expanduser(extension))
+            if os.path.exists(extension_to_add):
+                self._extension_files.append(extension_to_add)
+            else:
+                raise IOError("Path to the extension doesn't exist")
+        else:
+            raise ValueError("argument can not be null")
+
+    def add_encoded_extension(self, extension):
+        """
+        Adds Base64 encoded string with extension data to a list that will be used to extract it
+        to the ChromeDriver
+
+        :Args:
+         - extension: Base64 encoded string with extension data
+        """
+        if extension:
+            self._extensions.append(extension)
+        else:
+            raise ValueError("argument can not be null")
+
+    @property
+    def experimental_options(self):
+        """
+        Returns a dictionary of experimental options for chrome.
+        """
+        return self._experimental_options
+
+    def add_experimental_option(self, name, value):
+        """
+        Adds an experimental option which is passed to chrome.
+
+        Args:
+          name: The experimental option name.
+          value: The option value.
+        """
+        self._experimental_options[name] = value
+
+    @property
+    def headless(self):
+        """
+        Returns whether or not the headless argument is set
+        """
+        return '--headless' in self._arguments
+
+    @headless.setter
+    def headless(self, value):
+        """
+        Sets the headless argument
+
+        Args:
+          value: boolean value indicating to set the headless option
+        """
+        args = {'--headless'}
+        if platform.system().lower() == 'windows':
+            args.add('--disable-gpu')
+        if value is True:
+            self._arguments.extend(args)
+        else:
+            self._arguments = list(set(self._arguments) - args)
+
+    def set_headless(self, headless=True):
+        """ Deprecated, options.headless = True """
+        warnings.warn('use setter for headless property instead of set_headless',
+                      DeprecationWarning, stacklevel=2)
+        self.headless = headless
+
+    def to_capabilities(self):
+        """
+            Creates a capabilities with all the options that have been set and
+
+            returns a dictionary with everything
+        """
+        caps = self._caps
+        chrome_options = self.experimental_options.copy()
+        chrome_options["extensions"] = self.extensions
+        if self.binary_location:
+            chrome_options["binary"] = self.binary_location
+        chrome_options["args"] = self.arguments
+        if self.debugger_address:
+            chrome_options["debuggerAddress"] = self.debugger_address
+
+        caps[self.KEY] = chrome_options
+
+        return caps

+ 28 - 0
selenium-3.141.0/build/lib/selenium/webdriver/chrome/remote_connection.py

@@ -0,0 +1,28 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.remote.remote_connection import RemoteConnection
+
+
+class ChromeRemoteConnection(RemoteConnection):
+
+    def __init__(self, remote_server_addr, keep_alive=True):
+        RemoteConnection.__init__(self, remote_server_addr, keep_alive)
+        self._commands["launchApp"] = ('POST', '/session/$sessionId/chromium/launch_app')
+        self._commands["setNetworkConditions"] = ('POST', '/session/$sessionId/chromium/network_conditions')
+        self._commands["getNetworkConditions"] = ('GET', '/session/$sessionId/chromium/network_conditions')
+        self._commands['executeCdpCommand'] = ('POST', '/session/$sessionId/goog/cdp/execute')

+ 45 - 0
selenium-3.141.0/build/lib/selenium/webdriver/chrome/service.py

@@ -0,0 +1,45 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.common import service
+
+
+class Service(service.Service):
+    """
+    Object that manages the starting and stopping of the ChromeDriver
+    """
+
+    def __init__(self, executable_path, port=0, service_args=None,
+                 log_path=None, env=None):
+        """
+        Creates a new instance of the Service
+
+        :Args:
+         - executable_path : Path to the ChromeDriver
+         - port : Port the service is running on
+         - service_args : List of args to pass to the chromedriver service
+         - log_path : Path for the chromedriver service to log to"""
+
+        self.service_args = service_args or []
+        if log_path:
+            self.service_args.append('--log-path=%s' % log_path)
+
+        service.Service.__init__(self, executable_path, port=port, env=env,
+                                 start_error_message="Please see https://sites.google.com/a/chromium.org/chromedriver/home")
+
+    def command_line_args(self):
+        return ["--port=%d" % self.port] + self.service_args

+ 161 - 0
selenium-3.141.0/build/lib/selenium/webdriver/chrome/webdriver.py

@@ -0,0 +1,161 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import warnings
+
+from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
+from .remote_connection import ChromeRemoteConnection
+from .service import Service
+from .options import Options
+
+
+class WebDriver(RemoteWebDriver):
+    """
+    Controls the ChromeDriver and allows you to drive the browser.
+
+    You will need to download the ChromeDriver executable from
+    http://chromedriver.storage.googleapis.com/index.html
+    """
+
+    def __init__(self, executable_path="chromedriver", port=0,
+                 options=None, service_args=None,
+                 desired_capabilities=None, service_log_path=None,
+                 chrome_options=None, keep_alive=True):
+        """
+        Creates a new instance of the chrome driver.
+
+        Starts the service and then creates new instance of chrome driver.
+
+        :Args:
+         - executable_path - path to the executable. If the default is used it assumes the executable is in the $PATH
+         - port - port you would like the service to run, if left as 0, a free port will be found.
+         - options - this takes an instance of ChromeOptions
+         - service_args - List of args to pass to the driver service
+         - desired_capabilities - Dictionary object with non-browser specific
+           capabilities only, such as "proxy" or "loggingPref".
+         - service_log_path - Where to log information from the driver.
+         - chrome_options - Deprecated argument for options
+         - keep_alive - Whether to configure ChromeRemoteConnection to use HTTP keep-alive.
+        """
+        if chrome_options:
+            warnings.warn('use options instead of chrome_options',
+                          DeprecationWarning, stacklevel=2)
+            options = chrome_options
+
+        if options is None:
+            # desired_capabilities stays as passed in
+            if desired_capabilities is None:
+                desired_capabilities = self.create_options().to_capabilities()
+        else:
+            if desired_capabilities is None:
+                desired_capabilities = options.to_capabilities()
+            else:
+                desired_capabilities.update(options.to_capabilities())
+
+        self.service = Service(
+            executable_path,
+            port=port,
+            service_args=service_args,
+            log_path=service_log_path)
+        self.service.start()
+
+        try:
+            RemoteWebDriver.__init__(
+                self,
+                command_executor=ChromeRemoteConnection(
+                    remote_server_addr=self.service.service_url,
+                    keep_alive=keep_alive),
+                desired_capabilities=desired_capabilities)
+        except Exception:
+            self.quit()
+            raise
+        self._is_remote = False
+
+    def launch_app(self, id):
+        """Launches Chrome app specified by id."""
+        return self.execute("launchApp", {'id': id})
+
+    def get_network_conditions(self):
+        """
+        Gets Chrome network emulation settings.
+
+        :Returns:
+            A dict. For example:
+
+            {'latency': 4, 'download_throughput': 2, 'upload_throughput': 2,
+            'offline': False}
+
+        """
+        return self.execute("getNetworkConditions")['value']
+
+    def set_network_conditions(self, **network_conditions):
+        """
+        Sets Chrome network emulation settings.
+
+        :Args:
+         - network_conditions: A dict with conditions specification.
+
+        :Usage:
+            driver.set_network_conditions(
+                offline=False,
+                latency=5,  # additional latency (ms)
+                download_throughput=500 * 1024,  # maximal throughput
+                upload_throughput=500 * 1024)  # maximal throughput
+
+            Note: 'throughput' can be used to set both (for download and upload).
+        """
+        self.execute("setNetworkConditions", {
+            'network_conditions': network_conditions
+        })
+
+    def execute_cdp_cmd(self, cmd, cmd_args):
+        """
+        Execute Chrome Devtools Protocol command and get returned result
+
+        The command and command args should follow chrome devtools protocol domains/commands, refer to link
+        https://chromedevtools.github.io/devtools-protocol/
+
+        :Args:
+         - cmd: A str, command name
+         - cmd_args: A dict, command args. empty dict {} if there is no command args
+
+        :Usage:
+            driver.execute_cdp_cmd('Network.getResponseBody', {'requestId': requestId})
+
+        :Returns:
+            A dict, empty dict {} if there is no result to return.
+            For example to getResponseBody:
+
+            {'base64Encoded': False, 'body': 'response body string'}
+
+        """
+        return self.execute("executeCdpCommand", {'cmd': cmd, 'params': cmd_args})['value']
+
+    def quit(self):
+        """
+        Closes the browser and shuts down the ChromeDriver executable
+        that is started when starting the ChromeDriver
+        """
+        try:
+            RemoteWebDriver.quit(self)
+        except Exception:
+            # We don't care about the message because something probably has gone wrong
+            pass
+        finally:
+            self.service.stop()
+
+    def create_options(self):
+        return Options()

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 363 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/action_chains.py

@@ -0,0 +1,363 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+The ActionChains implementation,
+"""
+
+import time
+
+from selenium.webdriver.remote.command import Command
+
+from .utils import keys_to_typing
+from .actions.action_builder import ActionBuilder
+
+
+class ActionChains(object):
+    """
+    ActionChains are a way to automate low level interactions such as
+    mouse movements, mouse button actions, key press, and context menu interactions.
+    This is useful for doing more complex actions like hover over and drag and drop.
+
+    Generate user actions.
+       When you call methods for actions on the ActionChains object,
+       the actions are stored in a queue in the ActionChains object.
+       When you call perform(), the events are fired in the order they
+       are queued up.
+
+    ActionChains can be used in a chain pattern::
+
+        menu = driver.find_element_by_css_selector(".nav")
+        hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1")
+
+        ActionChains(driver).move_to_element(menu).click(hidden_submenu).perform()
+
+    Or actions can be queued up one by one, then performed.::
+
+        menu = driver.find_element_by_css_selector(".nav")
+        hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1")
+
+        actions = ActionChains(driver)
+        actions.move_to_element(menu)
+        actions.click(hidden_submenu)
+        actions.perform()
+
+    Either way, the actions are performed in the order they are called, one after
+    another.
+    """
+
+    def __init__(self, driver):
+        """
+        Creates a new ActionChains.
+
+        :Args:
+         - driver: The WebDriver instance which performs user actions.
+        """
+        self._driver = driver
+        self._actions = []
+        if self._driver.w3c:
+            self.w3c_actions = ActionBuilder(driver)
+
+    def perform(self):
+        """
+        Performs all stored actions.
+        """
+        if self._driver.w3c:
+            self.w3c_actions.perform()
+        else:
+            for action in self._actions:
+                action()
+
+    def reset_actions(self):
+        """
+            Clears actions that are already stored locally and on the remote end
+        """
+        if self._driver.w3c:
+            self.w3c_actions.clear_actions()
+        self._actions = []
+
+    def click(self, on_element=None):
+        """
+        Clicks an element.
+
+        :Args:
+         - on_element: The element to click.
+           If None, clicks on current mouse position.
+        """
+        if on_element:
+            self.move_to_element(on_element)
+        if self._driver.w3c:
+            self.w3c_actions.pointer_action.click()
+            self.w3c_actions.key_action.pause()
+            self.w3c_actions.key_action.pause()
+        else:
+            self._actions.append(lambda: self._driver.execute(
+                                 Command.CLICK, {'button': 0}))
+        return self
+
+    def click_and_hold(self, on_element=None):
+        """
+        Holds down the left mouse button on an element.
+
+        :Args:
+         - on_element: The element to mouse down.
+           If None, clicks on current mouse position.
+        """
+        if on_element:
+            self.move_to_element(on_element)
+        if self._driver.w3c:
+            self.w3c_actions.pointer_action.click_and_hold()
+            self.w3c_actions.key_action.pause()
+        else:
+            self._actions.append(lambda: self._driver.execute(
+                                 Command.MOUSE_DOWN, {}))
+        return self
+
+    def context_click(self, on_element=None):
+        """
+        Performs a context-click (right click) on an element.
+
+        :Args:
+         - on_element: The element to context-click.
+           If None, clicks on current mouse position.
+        """
+        if on_element:
+            self.move_to_element(on_element)
+        if self._driver.w3c:
+            self.w3c_actions.pointer_action.context_click()
+            self.w3c_actions.key_action.pause()
+            self.w3c_actions.key_action.pause()
+        else:
+            self._actions.append(lambda: self._driver.execute(
+                                 Command.CLICK, {'button': 2}))
+        return self
+
+    def double_click(self, on_element=None):
+        """
+        Double-clicks an element.
+
+        :Args:
+         - on_element: The element to double-click.
+           If None, clicks on current mouse position.
+        """
+        if on_element:
+            self.move_to_element(on_element)
+        if self._driver.w3c:
+            self.w3c_actions.pointer_action.double_click()
+            for _ in range(4):
+                self.w3c_actions.key_action.pause()
+        else:
+            self._actions.append(lambda: self._driver.execute(
+                                 Command.DOUBLE_CLICK, {}))
+        return self
+
+    def drag_and_drop(self, source, target):
+        """
+        Holds down the left mouse button on the source element,
+           then moves to the target element and releases the mouse button.
+
+        :Args:
+         - source: The element to mouse down.
+         - target: The element to mouse up.
+        """
+        self.click_and_hold(source)
+        self.release(target)
+        return self
+
+    def drag_and_drop_by_offset(self, source, xoffset, yoffset):
+        """
+        Holds down the left mouse button on the source element,
+           then moves to the target offset and releases the mouse button.
+
+        :Args:
+         - source: The element to mouse down.
+         - xoffset: X offset to move to.
+         - yoffset: Y offset to move to.
+        """
+        self.click_and_hold(source)
+        self.move_by_offset(xoffset, yoffset)
+        self.release()
+        return self
+
+    def key_down(self, value, element=None):
+        """
+        Sends a key press only, without releasing it.
+           Should only be used with modifier keys (Control, Alt and Shift).
+
+        :Args:
+         - value: The modifier key to send. Values are defined in `Keys` class.
+         - element: The element to send keys.
+           If None, sends a key to current focused element.
+
+        Example, pressing ctrl+c::
+
+            ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
+
+        """
+        if element:
+            self.click(element)
+        if self._driver.w3c:
+            self.w3c_actions.key_action.key_down(value)
+            self.w3c_actions.pointer_action.pause()
+        else:
+            self._actions.append(lambda: self._driver.execute(
+                Command.SEND_KEYS_TO_ACTIVE_ELEMENT,
+                {"value": keys_to_typing(value)}))
+        return self
+
+    def key_up(self, value, element=None):
+        """
+        Releases a modifier key.
+
+        :Args:
+         - value: The modifier key to send. Values are defined in Keys class.
+         - element: The element to send keys.
+           If None, sends a key to current focused element.
+
+        Example, pressing ctrl+c::
+
+            ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
+
+        """
+        if element:
+            self.click(element)
+        if self._driver.w3c:
+            self.w3c_actions.key_action.key_up(value)
+            self.w3c_actions.pointer_action.pause()
+        else:
+            self._actions.append(lambda: self._driver.execute(
+                Command.SEND_KEYS_TO_ACTIVE_ELEMENT,
+                {"value": keys_to_typing(value)}))
+        return self
+
+    def move_by_offset(self, xoffset, yoffset):
+        """
+        Moving the mouse to an offset from current mouse position.
+
+        :Args:
+         - xoffset: X offset to move to, as a positive or negative integer.
+         - yoffset: Y offset to move to, as a positive or negative integer.
+        """
+        if self._driver.w3c:
+            self.w3c_actions.pointer_action.move_by(xoffset, yoffset)
+            self.w3c_actions.key_action.pause()
+        else:
+            self._actions.append(lambda: self._driver.execute(
+                Command.MOVE_TO, {
+                    'xoffset': int(xoffset),
+                    'yoffset': int(yoffset)}))
+        return self
+
+    def move_to_element(self, to_element):
+        """
+        Moving the mouse to the middle of an element.
+
+        :Args:
+         - to_element: The WebElement to move to.
+        """
+        if self._driver.w3c:
+            self.w3c_actions.pointer_action.move_to(to_element)
+            self.w3c_actions.key_action.pause()
+        else:
+            self._actions.append(lambda: self._driver.execute(
+                                 Command.MOVE_TO, {'element': to_element.id}))
+        return self
+
+    def move_to_element_with_offset(self, to_element, xoffset, yoffset):
+        """
+        Move the mouse by an offset of the specified element.
+           Offsets are relative to the top-left corner of the element.
+
+        :Args:
+         - to_element: The WebElement to move to.
+         - xoffset: X offset to move to.
+         - yoffset: Y offset to move to.
+        """
+        if self._driver.w3c:
+            self.w3c_actions.pointer_action.move_to(to_element, xoffset, yoffset)
+            self.w3c_actions.key_action.pause()
+        else:
+            self._actions.append(
+                lambda: self._driver.execute(Command.MOVE_TO, {
+                    'element': to_element.id,
+                    'xoffset': int(xoffset),
+                    'yoffset': int(yoffset)}))
+        return self
+
+    def pause(self, seconds):
+        """ Pause all inputs for the specified duration in seconds """
+        if self._driver.w3c:
+            self.w3c_actions.pointer_action.pause(seconds)
+            self.w3c_actions.key_action.pause(seconds)
+        else:
+            self._actions.append(lambda: time.sleep(seconds))
+        return self
+
+    def release(self, on_element=None):
+        """
+        Releasing a held mouse button on an element.
+
+        :Args:
+         - on_element: The element to mouse up.
+           If None, releases on current mouse position.
+        """
+        if on_element:
+            self.move_to_element(on_element)
+        if self._driver.w3c:
+            self.w3c_actions.pointer_action.release()
+            self.w3c_actions.key_action.pause()
+        else:
+            self._actions.append(lambda: self._driver.execute(Command.MOUSE_UP, {}))
+        return self
+
+    def send_keys(self, *keys_to_send):
+        """
+        Sends keys to current focused element.
+
+        :Args:
+         - keys_to_send: The keys to send.  Modifier keys constants can be found in the
+           'Keys' class.
+        """
+        typing = keys_to_typing(keys_to_send)
+        if self._driver.w3c:
+            for key in typing:
+                self.key_down(key)
+                self.key_up(key)
+        else:
+            self._actions.append(lambda: self._driver.execute(
+                Command.SEND_KEYS_TO_ACTIVE_ELEMENT, {'value': typing}))
+        return self
+
+    def send_keys_to_element(self, element, *keys_to_send):
+        """
+        Sends keys to an element.
+
+        :Args:
+         - element: The element to send keys.
+         - keys_to_send: The keys to send.  Modifier keys constants can be found in the
+           'Keys' class.
+        """
+        self.click(element)
+        self.send_keys(*keys_to_send)
+        return self
+
+    # Context manager so ActionChains can be used in a 'with .. as' statements.
+    def __enter__(self):
+        return self  # Return created instance of self.
+
+    def __exit__(self, _type, _value, _traceback):
+        pass  # Do nothing, does not require additional cleanup.

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/actions/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 85 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/actions/action_builder.py

@@ -0,0 +1,85 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.remote.command import Command
+from . import interaction
+from .key_actions import KeyActions
+from .key_input import KeyInput
+from .pointer_actions import PointerActions
+from .pointer_input import PointerInput
+
+
+class ActionBuilder(object):
+    def __init__(self, driver, mouse=None, keyboard=None):
+        if mouse is None:
+            mouse = PointerInput(interaction.POINTER_MOUSE, "mouse")
+        if keyboard is None:
+            keyboard = KeyInput(interaction.KEY)
+        self.devices = [mouse, keyboard]
+        self._key_action = KeyActions(keyboard)
+        self._pointer_action = PointerActions(mouse)
+        self.driver = driver
+
+    def get_device_with(self, name):
+        try:
+            idx = self.devices.index(name)
+            return self.devices[idx]
+        except:
+            pass
+
+    @property
+    def pointer_inputs(self):
+        return [device for device in self.devices if device.type == interaction.POINTER]
+
+    @property
+    def key_inputs(self):
+        return [device for device in self.devices if device.type == interaction.KEY]
+
+    @property
+    def key_action(self):
+        return self._key_action
+
+    @property
+    def pointer_action(self):
+        return self._pointer_action
+
+    def add_key_input(self, name):
+        new_input = KeyInput(name)
+        self._add_input(new_input)
+        return new_input
+
+    def add_pointer_input(self, kind, name):
+        new_input = PointerInput(kind, name)
+        self._add_input(new_input)
+        return new_input
+
+    def perform(self):
+        enc = {"actions": []}
+        for device in self.devices:
+            encoded = device.encode()
+            if encoded['actions']:
+                enc["actions"].append(encoded)
+        self.driver.execute(Command.W3C_ACTIONS, enc)
+
+    def clear_actions(self):
+        """
+            Clears actions that are already stored on the remote end
+        """
+        self.driver.execute(Command.W3C_CLEAR_ACTIONS)
+
+    def _add_input(self, input):
+        self.devices.append(input)

+ 43 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/actions/input_device.py

@@ -0,0 +1,43 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import uuid
+
+
+class InputDevice(object):
+    """
+        Describes the input device being used for the action.
+    """
+    def __init__(self, name=None):
+        if name is None:
+            self.name = uuid.uuid4()
+        else:
+            self.name = name
+
+        self.actions = []
+
+    def add_action(self, action):
+        """
+
+        """
+        self.actions.append(action)
+
+    def clear_actions(self):
+        self.actions = []
+
+    def create_pause(self, duraton=0):
+        pass

+ 50 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/actions/interaction.py

@@ -0,0 +1,50 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+KEY = "key"
+POINTER = "pointer"
+NONE = "none"
+SOURCE_TYPES = set([KEY, POINTER, NONE])
+
+POINTER_MOUSE = "mouse"
+POINTER_TOUCH = "touch"
+POINTER_PEN = "pen"
+
+POINTER_KINDS = set([POINTER_MOUSE, POINTER_TOUCH, POINTER_PEN])
+
+
+class Interaction(object):
+
+    PAUSE = "pause"
+
+    def __init__(self, source):
+        self.source = source
+
+
+class Pause(Interaction):
+
+    def __init__(self, source, duration=0):
+        super(Interaction, self).__init__()
+        self.source = source
+        self.duration = duration
+
+    def encode(self):
+        return {
+            "type": self.PAUSE,
+            "duration": int(self.duration * 1000)
+        }

+ 50 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/actions/key_actions.py

@@ -0,0 +1,50 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from .interaction import Interaction, KEY
+from .key_input import KeyInput
+from ..utils import keys_to_typing
+
+
+class KeyActions(Interaction):
+
+    def __init__(self, source=None):
+        if source is None:
+            source = KeyInput(KEY)
+        self.source = source
+        super(KeyActions, self).__init__(source)
+
+    def key_down(self, letter):
+        return self._key_action("create_key_down", letter)
+
+    def key_up(self, letter):
+        return self._key_action("create_key_up", letter)
+
+    def pause(self, duration=0):
+        return self._key_action("create_pause", duration)
+
+    def send_keys(self, text):
+        if not isinstance(text, list):
+            text = keys_to_typing(text)
+        for letter in text:
+            self.key_down(letter)
+            self.key_up(letter)
+        return self
+
+    def _key_action(self, action, letter):
+        meth = getattr(self.source, action)
+        meth(letter)
+        return self

+ 51 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/actions/key_input.py

@@ -0,0 +1,51 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from . import interaction
+
+from .input_device import InputDevice
+from .interaction import (Interaction,
+                          Pause)
+
+
+class KeyInput(InputDevice):
+    def __init__(self, name):
+        super(KeyInput, self).__init__()
+        self.name = name
+        self.type = interaction.KEY
+
+    def encode(self):
+        return {"type": self.type, "id": self.name, "actions": [acts.encode() for acts in self.actions]}
+
+    def create_key_down(self, key):
+        self.add_action(TypingInteraction(self, "keyDown", key))
+
+    def create_key_up(self, key):
+        self.add_action(TypingInteraction(self, "keyUp", key))
+
+    def create_pause(self, pause_duration=0):
+        self.add_action(Pause(self, pause_duration))
+
+
+class TypingInteraction(Interaction):
+
+    def __init__(self, source, type_, key):
+        super(TypingInteraction, self).__init__(source)
+        self.type = type_
+        self.key = key
+
+    def encode(self):
+        return {"type": self.type, "value": self.key}

+ 5 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/actions/mouse_button.py

@@ -0,0 +1,5 @@
+class MouseButton(object):
+
+    LEFT = 0
+    MIDDLE = 1
+    RIGHT = 2

+ 100 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/actions/pointer_actions.py

@@ -0,0 +1,100 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from . import interaction
+
+from .interaction import Interaction
+from .mouse_button import MouseButton
+from .pointer_input import PointerInput
+
+from selenium.webdriver.remote.webelement import WebElement
+
+
+class PointerActions(Interaction):
+
+    def __init__(self, source=None):
+        if source is None:
+            source = PointerInput(interaction.POINTER_MOUSE, "mouse")
+        self.source = source
+        super(PointerActions, self).__init__(source)
+
+    def pointer_down(self, button=MouseButton.LEFT):
+        self._button_action("create_pointer_down", button=button)
+
+    def pointer_up(self, button=MouseButton.LEFT):
+        self._button_action("create_pointer_up", button=button)
+
+    def move_to(self, element, x=None, y=None):
+        if not isinstance(element, WebElement):
+            raise AttributeError("move_to requires a WebElement")
+        if x is not None or y is not None:
+            el_rect = element.rect
+            left_offset = el_rect['width'] / 2
+            top_offset = el_rect['height'] / 2
+            left = -left_offset + (x or 0)
+            top = -top_offset + (y or 0)
+        else:
+            left = 0
+            top = 0
+        self.source.create_pointer_move(origin=element, x=int(left), y=int(top))
+        return self
+
+    def move_by(self, x, y):
+        self.source.create_pointer_move(origin=interaction.POINTER, x=int(x), y=int(y))
+        return self
+
+    def move_to_location(self, x, y):
+        self.source.create_pointer_move(origin='viewport', x=int(x), y=int(y))
+        return self
+
+    def click(self, element=None):
+        if element:
+            self.move_to(element)
+        self.pointer_down(MouseButton.LEFT)
+        self.pointer_up(MouseButton.LEFT)
+        return self
+
+    def context_click(self, element=None):
+        if element:
+            self.move_to(element)
+        self.pointer_down(MouseButton.RIGHT)
+        self.pointer_up(MouseButton.RIGHT)
+        return self
+
+    def click_and_hold(self, element=None):
+        if element:
+            self.move_to(element)
+        self.pointer_down()
+        return self
+
+    def release(self):
+        self.pointer_up()
+        return self
+
+    def double_click(self, element=None):
+        if element:
+            self.move_to(element)
+        self.click()
+        self.click()
+
+    def pause(self, duration=0):
+        self.source.create_pause(duration)
+        return self
+
+    def _button_action(self, action, button=MouseButton.LEFT):
+        meth = getattr(self.source, action)
+        meth(button)
+        return self

+ 63 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/actions/pointer_input.py

@@ -0,0 +1,63 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from .input_device import InputDevice
+from .interaction import POINTER, POINTER_KINDS
+
+from selenium.common.exceptions import InvalidArgumentException
+from selenium.webdriver.remote.webelement import WebElement
+
+
+class PointerInput(InputDevice):
+
+    DEFAULT_MOVE_DURATION = 250
+
+    def __init__(self, kind, name):
+        super(PointerInput, self).__init__()
+        if (kind not in POINTER_KINDS):
+            raise InvalidArgumentException("Invalid PointerInput kind '%s'" % kind)
+        self.type = POINTER
+        self.kind = kind
+        self.name = name
+
+    def create_pointer_move(self, duration=DEFAULT_MOVE_DURATION, x=None, y=None, origin=None):
+        action = dict(type="pointerMove", duration=duration)
+        action["x"] = x
+        action["y"] = y
+        if isinstance(origin, WebElement):
+            action["origin"] = {"element-6066-11e4-a52e-4f735466cecf": origin.id}
+        elif origin is not None:
+            action["origin"] = origin
+
+        self.add_action(action)
+
+    def create_pointer_down(self, button):
+        self.add_action({"type": "pointerDown", "duration": 0, "button": button})
+
+    def create_pointer_up(self, button):
+        self.add_action({"type": "pointerUp", "duration": 0, "button": button})
+
+    def create_pointer_cancel(self):
+        self.add_action({"type": "pointerCancel"})
+
+    def create_pause(self, pause_duration):
+        self.add_action({"type": "pause", "duration": int(pause_duration * 1000)})
+
+    def encode(self):
+        return {"type": self.type,
+                "parameters": {"pointerType": self.kind},
+                "id": self.name,
+                "actions": [acts for acts in self.actions]}

+ 105 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/alert.py

@@ -0,0 +1,105 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+The Alert implementation.
+"""
+
+from selenium.webdriver.common.utils import keys_to_typing
+from selenium.webdriver.remote.command import Command
+
+
+class Alert(object):
+    """
+    Allows to work with alerts.
+
+    Use this class to interact with alert prompts.  It contains methods for dismissing,
+    accepting, inputting, and getting text from alert prompts.
+
+    Accepting / Dismissing alert prompts::
+
+        Alert(driver).accept()
+        Alert(driver).dismiss()
+
+    Inputting a value into an alert prompt:
+
+        name_prompt = Alert(driver)
+        name_prompt.send_keys("Willian Shakesphere")
+        name_prompt.accept()
+
+
+    Reading a the text of a prompt for verification:
+
+        alert_text = Alert(driver).text
+        self.assertEqual("Do you wish to quit?", alert_text)
+
+    """
+
+    def __init__(self, driver):
+        """
+        Creates a new Alert.
+
+        :Args:
+         - driver: The WebDriver instance which performs user actions.
+        """
+        self.driver = driver
+
+    @property
+    def text(self):
+        """
+        Gets the text of the Alert.
+        """
+        if self.driver.w3c:
+            return self.driver.execute(Command.W3C_GET_ALERT_TEXT)["value"]
+        else:
+            return self.driver.execute(Command.GET_ALERT_TEXT)["value"]
+
+    def dismiss(self):
+        """
+        Dismisses the alert available.
+        """
+        if self.driver.w3c:
+            self.driver.execute(Command.W3C_DISMISS_ALERT)
+        else:
+            self.driver.execute(Command.DISMISS_ALERT)
+
+    def accept(self):
+        """
+        Accepts the alert available.
+
+        Usage::
+        Alert(driver).accept() # Confirm a alert dialog.
+        """
+        if self.driver.w3c:
+            self.driver.execute(Command.W3C_ACCEPT_ALERT)
+        else:
+            self.driver.execute(Command.ACCEPT_ALERT)
+
+    def send_keys(self, keysToSend):
+        """
+        Send Keys to the Alert.
+
+        :Args:
+         - keysToSend: The text to be sent to Alert.
+
+
+        """
+        if self.driver.w3c:
+            self.driver.execute(Command.W3C_SET_ALERT_VALUE, {'value': keys_to_typing(keysToSend),
+                                                              'text': keysToSend})
+        else:
+            self.driver.execute(Command.SET_ALERT_VALUE, {'text': keysToSend})

+ 35 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/by.py

@@ -0,0 +1,35 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+The By implementation.
+"""
+
+
+class By(object):
+    """
+    Set of supported locator strategies.
+    """
+
+    ID = "id"
+    XPATH = "xpath"
+    LINK_TEXT = "link text"
+    PARTIAL_LINK_TEXT = "partial link text"
+    NAME = "name"
+    TAG_NAME = "tag name"
+    CLASS_NAME = "class name"
+    CSS_SELECTOR = "css selector"

+ 128 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/desired_capabilities.py

@@ -0,0 +1,128 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+The Desired Capabilities implementation.
+"""
+
+
+class DesiredCapabilities(object):
+    """
+    Set of default supported desired capabilities.
+
+    Use this as a starting point for creating a desired capabilities object for
+    requesting remote webdrivers for connecting to selenium server or selenium grid.
+
+    Usage Example::
+
+        from selenium import webdriver
+
+        selenium_grid_url = "http://198.0.0.1:4444/wd/hub"
+
+        # Create a desired capabilities object as a starting point.
+        capabilities = DesiredCapabilities.FIREFOX.copy()
+        capabilities['platform'] = "WINDOWS"
+        capabilities['version'] = "10"
+
+        # Instantiate an instance of Remote WebDriver with the desired capabilities.
+        driver = webdriver.Remote(desired_capabilities=capabilities,
+                                  command_executor=selenium_grid_url)
+
+    Note: Always use '.copy()' on the DesiredCapabilities object to avoid the side
+    effects of altering the Global class instance.
+
+    """
+
+    FIREFOX = {
+        "browserName": "firefox",
+        "marionette": True,
+        "acceptInsecureCerts": True,
+    }
+
+    INTERNETEXPLORER = {
+        "browserName": "internet explorer",
+        "version": "",
+        "platform": "WINDOWS",
+    }
+
+    EDGE = {
+        "browserName": "MicrosoftEdge",
+        "version": "",
+        "platform": "WINDOWS"
+    }
+
+    CHROME = {
+        "browserName": "chrome",
+        "version": "",
+        "platform": "ANY",
+    }
+
+    OPERA = {
+        "browserName": "opera",
+        "version": "",
+        "platform": "ANY",
+    }
+
+    SAFARI = {
+        "browserName": "safari",
+        "version": "",
+        "platform": "MAC",
+    }
+
+    HTMLUNIT = {
+        "browserName": "htmlunit",
+        "version": "",
+        "platform": "ANY",
+    }
+
+    HTMLUNITWITHJS = {
+        "browserName": "htmlunit",
+        "version": "firefox",
+        "platform": "ANY",
+        "javascriptEnabled": True,
+    }
+
+    IPHONE = {
+        "browserName": "iPhone",
+        "version": "",
+        "platform": "MAC",
+    }
+
+    IPAD = {
+        "browserName": "iPad",
+        "version": "",
+        "platform": "MAC",
+    }
+
+    ANDROID = {
+        "browserName": "android",
+        "version": "",
+        "platform": "ANDROID",
+    }
+
+    PHANTOMJS = {
+        "browserName": "phantomjs",
+        "version": "",
+        "platform": "ANY",
+        "javascriptEnabled": True,
+    }
+
+    WEBKITGTK = {
+        "browserName": "MiniBrowser",
+        "version": "",
+        "platform": "ANY",
+    }

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/html5/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 48 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/html5/application_cache.py

@@ -0,0 +1,48 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+The ApplicationCache implementaion.
+"""
+
+from selenium.webdriver.remote.command import Command
+
+
+class ApplicationCache(object):
+
+    UNCACHED = 0
+    IDLE = 1
+    CHECKING = 2
+    DOWNLOADING = 3
+    UPDATE_READY = 4
+    OBSOLETE = 5
+
+    def __init__(self, driver):
+        """
+        Creates a new Aplication Cache.
+
+        :Args:
+         - driver: The WebDriver instance which performs user actions.
+        """
+        self.driver = driver
+
+    @property
+    def status(self):
+        """
+        Returns a current status of application cache.
+        """
+        return self.driver.execute(Command.GET_APP_CACHE_STATUS)['value']

+ 96 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/keys.py

@@ -0,0 +1,96 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+The Keys implementation.
+"""
+
+from __future__ import unicode_literals
+
+
+class Keys(object):
+    """
+    Set of special keys codes.
+    """
+
+    NULL = '\ue000'
+    CANCEL = '\ue001'  # ^break
+    HELP = '\ue002'
+    BACKSPACE = '\ue003'
+    BACK_SPACE = BACKSPACE
+    TAB = '\ue004'
+    CLEAR = '\ue005'
+    RETURN = '\ue006'
+    ENTER = '\ue007'
+    SHIFT = '\ue008'
+    LEFT_SHIFT = SHIFT
+    CONTROL = '\ue009'
+    LEFT_CONTROL = CONTROL
+    ALT = '\ue00a'
+    LEFT_ALT = ALT
+    PAUSE = '\ue00b'
+    ESCAPE = '\ue00c'
+    SPACE = '\ue00d'
+    PAGE_UP = '\ue00e'
+    PAGE_DOWN = '\ue00f'
+    END = '\ue010'
+    HOME = '\ue011'
+    LEFT = '\ue012'
+    ARROW_LEFT = LEFT
+    UP = '\ue013'
+    ARROW_UP = UP
+    RIGHT = '\ue014'
+    ARROW_RIGHT = RIGHT
+    DOWN = '\ue015'
+    ARROW_DOWN = DOWN
+    INSERT = '\ue016'
+    DELETE = '\ue017'
+    SEMICOLON = '\ue018'
+    EQUALS = '\ue019'
+
+    NUMPAD0 = '\ue01a'  # number pad keys
+    NUMPAD1 = '\ue01b'
+    NUMPAD2 = '\ue01c'
+    NUMPAD3 = '\ue01d'
+    NUMPAD4 = '\ue01e'
+    NUMPAD5 = '\ue01f'
+    NUMPAD6 = '\ue020'
+    NUMPAD7 = '\ue021'
+    NUMPAD8 = '\ue022'
+    NUMPAD9 = '\ue023'
+    MULTIPLY = '\ue024'
+    ADD = '\ue025'
+    SEPARATOR = '\ue026'
+    SUBTRACT = '\ue027'
+    DECIMAL = '\ue028'
+    DIVIDE = '\ue029'
+
+    F1 = '\ue031'  # function  keys
+    F2 = '\ue032'
+    F3 = '\ue033'
+    F4 = '\ue034'
+    F5 = '\ue035'
+    F6 = '\ue036'
+    F7 = '\ue037'
+    F8 = '\ue038'
+    F9 = '\ue039'
+    F10 = '\ue03a'
+    F11 = '\ue03b'
+    F12 = '\ue03c'
+
+    META = '\ue03d'
+    COMMAND = '\ue03d'

+ 334 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/proxy.py

@@ -0,0 +1,334 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+The Proxy implementation.
+"""
+
+
+class ProxyTypeFactory:
+    """
+    Factory for proxy types.
+    """
+
+    @staticmethod
+    def make(ff_value, string):
+        return {'ff_value': ff_value, 'string': string}
+
+
+class ProxyType:
+    """
+    Set of possible types of proxy.
+
+    Each proxy type has 2 properties:
+       'ff_value' is value of Firefox profile preference,
+       'string' is id of proxy type.
+    """
+
+    DIRECT = ProxyTypeFactory.make(0, 'DIRECT')  # Direct connection, no proxy (default on Windows).
+    MANUAL = ProxyTypeFactory.make(1, 'MANUAL')  # Manual proxy settings (e.g., for httpProxy).
+    PAC = ProxyTypeFactory.make(2, 'PAC')  # Proxy autoconfiguration from URL.
+    RESERVED_1 = ProxyTypeFactory.make(3, 'RESERVED1')  # Never used.
+    AUTODETECT = ProxyTypeFactory.make(4, 'AUTODETECT')  # Proxy autodetection (presumably with WPAD).
+    SYSTEM = ProxyTypeFactory.make(5, 'SYSTEM')  # Use system settings (default on Linux).
+    UNSPECIFIED = ProxyTypeFactory.make(6, 'UNSPECIFIED')  # Not initialized (for internal use).
+
+    @classmethod
+    def load(cls, value):
+        if isinstance(value, dict) and 'string' in value:
+            value = value['string']
+        value = str(value).upper()
+        for attr in dir(cls):
+            attr_value = getattr(cls, attr)
+            if isinstance(attr_value, dict) and \
+                    'string' in attr_value and \
+                    attr_value['string'] is not None and \
+                    attr_value['string'] == value:
+                return attr_value
+        raise Exception("No proxy type is found for %s" % (value))
+
+
+class Proxy(object):
+    """
+    Proxy contains information about proxy type and necessary proxy settings.
+    """
+
+    proxyType = ProxyType.UNSPECIFIED
+    autodetect = False
+    ftpProxy = ''
+    httpProxy = ''
+    noProxy = ''
+    proxyAutoconfigUrl = ''
+    sslProxy = ''
+    socksProxy = ''
+    socksUsername = ''
+    socksPassword = ''
+
+    def __init__(self, raw=None):
+        """
+        Creates a new Proxy.
+
+        :Args:
+         - raw: raw proxy data. If None, default class values are used.
+        """
+        if raw is not None:
+            if 'proxyType' in raw and raw['proxyType'] is not None:
+                self.proxy_type = ProxyType.load(raw['proxyType'])
+            if 'ftpProxy' in raw and raw['ftpProxy'] is not None:
+                self.ftp_proxy = raw['ftpProxy']
+            if 'httpProxy' in raw and raw['httpProxy'] is not None:
+                self.http_proxy = raw['httpProxy']
+            if 'noProxy' in raw and raw['noProxy'] is not None:
+                self.no_proxy = raw['noProxy']
+            if 'proxyAutoconfigUrl' in raw and raw['proxyAutoconfigUrl'] is not None:
+                self.proxy_autoconfig_url = raw['proxyAutoconfigUrl']
+            if 'sslProxy' in raw and raw['sslProxy'] is not None:
+                self.sslProxy = raw['sslProxy']
+            if 'autodetect' in raw and raw['autodetect'] is not None:
+                self.auto_detect = raw['autodetect']
+            if 'socksProxy' in raw and raw['socksProxy'] is not None:
+                self.socks_proxy = raw['socksProxy']
+            if 'socksUsername' in raw and raw['socksUsername'] is not None:
+                self.socks_username = raw['socksUsername']
+            if 'socksPassword' in raw and raw['socksPassword'] is not None:
+                self.socks_password = raw['socksPassword']
+
+    @property
+    def proxy_type(self):
+        """
+        Returns proxy type as `ProxyType`.
+        """
+        return self.proxyType
+
+    @proxy_type.setter
+    def proxy_type(self, value):
+        """
+        Sets proxy type.
+
+        :Args:
+         - value: The proxy type.
+        """
+        self._verify_proxy_type_compatibility(value)
+        self.proxyType = value
+
+    @property
+    def auto_detect(self):
+        """
+        Returns autodetect setting.
+        """
+        return self.autodetect
+
+    @auto_detect.setter
+    def auto_detect(self, value):
+        """
+        Sets autodetect setting.
+
+        :Args:
+         - value: The autodetect value.
+        """
+        if isinstance(value, bool):
+            if self.autodetect is not value:
+                self._verify_proxy_type_compatibility(ProxyType.AUTODETECT)
+                self.proxyType = ProxyType.AUTODETECT
+                self.autodetect = value
+        else:
+            raise ValueError("Autodetect proxy value needs to be a boolean")
+
+    @property
+    def ftp_proxy(self):
+        """
+        Returns ftp proxy setting.
+        """
+        return self.ftpProxy
+
+    @ftp_proxy.setter
+    def ftp_proxy(self, value):
+        """
+        Sets ftp proxy setting.
+
+        :Args:
+         - value: The ftp proxy value.
+        """
+        self._verify_proxy_type_compatibility(ProxyType.MANUAL)
+        self.proxyType = ProxyType.MANUAL
+        self.ftpProxy = value
+
+    @property
+    def http_proxy(self):
+        """
+        Returns http proxy setting.
+        """
+        return self.httpProxy
+
+    @http_proxy.setter
+    def http_proxy(self, value):
+        """
+        Sets http proxy setting.
+
+        :Args:
+         - value: The http proxy value.
+        """
+        self._verify_proxy_type_compatibility(ProxyType.MANUAL)
+        self.proxyType = ProxyType.MANUAL
+        self.httpProxy = value
+
+    @property
+    def no_proxy(self):
+        """
+        Returns noproxy setting.
+        """
+        return self.noProxy
+
+    @no_proxy.setter
+    def no_proxy(self, value):
+        """
+        Sets noproxy setting.
+
+        :Args:
+         - value: The noproxy value.
+        """
+        self._verify_proxy_type_compatibility(ProxyType.MANUAL)
+        self.proxyType = ProxyType.MANUAL
+        self.noProxy = value
+
+    @property
+    def proxy_autoconfig_url(self):
+        """
+        Returns proxy autoconfig url setting.
+        """
+        return self.proxyAutoconfigUrl
+
+    @proxy_autoconfig_url.setter
+    def proxy_autoconfig_url(self, value):
+        """
+        Sets proxy autoconfig url setting.
+
+        :Args:
+         - value: The proxy autoconfig url value.
+        """
+        self._verify_proxy_type_compatibility(ProxyType.PAC)
+        self.proxyType = ProxyType.PAC
+        self.proxyAutoconfigUrl = value
+
+    @property
+    def ssl_proxy(self):
+        """
+        Returns https proxy setting.
+        """
+        return self.sslProxy
+
+    @ssl_proxy.setter
+    def ssl_proxy(self, value):
+        """
+        Sets https proxy setting.
+
+        :Args:
+         - value: The https proxy value.
+        """
+        self._verify_proxy_type_compatibility(ProxyType.MANUAL)
+        self.proxyType = ProxyType.MANUAL
+        self.sslProxy = value
+
+    @property
+    def socks_proxy(self):
+        """
+        Returns socks proxy setting.
+        """
+        return self.socksProxy
+
+    @socks_proxy.setter
+    def socks_proxy(self, value):
+        """
+        Sets socks proxy setting.
+
+        :Args:
+         - value: The socks proxy value.
+        """
+        self._verify_proxy_type_compatibility(ProxyType.MANUAL)
+        self.proxyType = ProxyType.MANUAL
+        self.socksProxy = value
+
+    @property
+    def socks_username(self):
+        """
+        Returns socks proxy username setting.
+        """
+        return self.socksUsername
+
+    @socks_username.setter
+    def socks_username(self, value):
+        """
+        Sets socks proxy username setting.
+
+        :Args:
+         - value: The socks proxy username value.
+        """
+        self._verify_proxy_type_compatibility(ProxyType.MANUAL)
+        self.proxyType = ProxyType.MANUAL
+        self.socksUsername = value
+
+    @property
+    def socks_password(self):
+        """
+        Returns socks proxy password setting.
+        """
+        return self.socksPassword
+
+    @socks_password.setter
+    def socks_password(self, value):
+        """
+        Sets socks proxy password setting.
+
+        :Args:
+         - value: The socks proxy password value.
+        """
+        self._verify_proxy_type_compatibility(ProxyType.MANUAL)
+        self.proxyType = ProxyType.MANUAL
+        self.socksPassword = value
+
+    def _verify_proxy_type_compatibility(self, compatibleProxy):
+        if self.proxyType != ProxyType.UNSPECIFIED and self.proxyType != compatibleProxy:
+            raise Exception(" Specified proxy type (%s) not compatible with current setting (%s)" % (compatibleProxy, self.proxyType))
+
+    def add_to_capabilities(self, capabilities):
+        """
+        Adds proxy information as capability in specified capabilities.
+
+        :Args:
+         - capabilities: The capabilities to which proxy will be added.
+        """
+        proxy_caps = {}
+        proxy_caps['proxyType'] = self.proxyType['string']
+        if self.autodetect:
+            proxy_caps['autodetect'] = self.autodetect
+        if self.ftpProxy:
+            proxy_caps['ftpProxy'] = self.ftpProxy
+        if self.httpProxy:
+            proxy_caps['httpProxy'] = self.httpProxy
+        if self.proxyAutoconfigUrl:
+            proxy_caps['proxyAutoconfigUrl'] = self.proxyAutoconfigUrl
+        if self.sslProxy:
+            proxy_caps['sslProxy'] = self.sslProxy
+        if self.noProxy:
+            proxy_caps['noProxy'] = self.noProxy
+        if self.socksProxy:
+            proxy_caps['socksProxy'] = self.socksProxy
+        if self.socksUsername:
+            proxy_caps['socksUsername'] = self.socksUsername
+        if self.socksPassword:
+            proxy_caps['socksPassword'] = self.socksPassword
+        capabilities['proxy'] = proxy_caps

+ 178 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/service.py

@@ -0,0 +1,178 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import errno
+import os
+import platform
+import subprocess
+from subprocess import PIPE
+import time
+from selenium.common.exceptions import WebDriverException
+from selenium.webdriver.common import utils
+
+try:
+    from subprocess import DEVNULL
+    _HAS_NATIVE_DEVNULL = True
+except ImportError:
+    DEVNULL = -3
+    _HAS_NATIVE_DEVNULL = False
+
+
+class Service(object):
+
+    def __init__(self, executable, port=0, log_file=DEVNULL, env=None, start_error_message=""):
+        self.path = executable
+
+        self.port = port
+        if self.port == 0:
+            self.port = utils.free_port()
+
+        if not _HAS_NATIVE_DEVNULL and log_file == DEVNULL:
+            log_file = open(os.devnull, 'wb')
+
+        self.start_error_message = start_error_message
+        self.log_file = log_file
+        self.env = env or os.environ
+
+    @property
+    def service_url(self):
+        """
+        Gets the url of the Service
+        """
+        return "http://%s" % utils.join_host_port('localhost', self.port)
+
+    def command_line_args(self):
+        raise NotImplemented("This method needs to be implemented in a sub class")
+
+    def start(self):
+        """
+        Starts the Service.
+
+        :Exceptions:
+         - WebDriverException : Raised either when it can't start the service
+           or when it can't connect to the service
+        """
+        try:
+            cmd = [self.path]
+            cmd.extend(self.command_line_args())
+            self.process = subprocess.Popen(cmd, env=self.env,
+                                            close_fds=platform.system() != 'Windows',
+                                            stdout=self.log_file,
+                                            stderr=self.log_file,
+                                            stdin=PIPE)
+        except TypeError:
+            raise
+        except OSError as err:
+            if err.errno == errno.ENOENT:
+                raise WebDriverException(
+                    "'%s' executable needs to be in PATH. %s" % (
+                        os.path.basename(self.path), self.start_error_message)
+                )
+            elif err.errno == errno.EACCES:
+                raise WebDriverException(
+                    "'%s' executable may have wrong permissions. %s" % (
+                        os.path.basename(self.path), self.start_error_message)
+                )
+            else:
+                raise
+        except Exception as e:
+            raise WebDriverException(
+                "The executable %s needs to be available in the path. %s\n%s" %
+                (os.path.basename(self.path), self.start_error_message, str(e)))
+        count = 0
+        while True:
+            self.assert_process_still_running()
+            if self.is_connectable():
+                break
+            count += 1
+            time.sleep(1)
+            if count == 30:
+                raise WebDriverException("Can not connect to the Service %s" % self.path)
+
+    def assert_process_still_running(self):
+        return_code = self.process.poll()
+        if return_code is not None:
+            raise WebDriverException(
+                'Service %s unexpectedly exited. Status code was: %s'
+                % (self.path, return_code)
+            )
+
+    def is_connectable(self):
+        return utils.is_connectable(self.port)
+
+    def send_remote_shutdown_command(self):
+        try:
+            from urllib import request as url_request
+            URLError = url_request.URLError
+        except ImportError:
+            import urllib2 as url_request
+            import urllib2
+            URLError = urllib2.URLError
+
+        try:
+            url_request.urlopen("%s/shutdown" % self.service_url)
+        except URLError:
+            return
+
+        for x in range(30):
+            if not self.is_connectable():
+                break
+            else:
+                time.sleep(1)
+
+    def stop(self):
+        """
+        Stops the service.
+        """
+        if self.log_file != PIPE and not (self.log_file == DEVNULL and _HAS_NATIVE_DEVNULL):
+            try:
+                self.log_file.close()
+            except Exception:
+                pass
+
+        if self.process is None:
+            return
+
+        try:
+            self.send_remote_shutdown_command()
+        except TypeError:
+            pass
+
+        try:
+            if self.process:
+                for stream in [self.process.stdin,
+                               self.process.stdout,
+                               self.process.stderr]:
+                    try:
+                        stream.close()
+                    except AttributeError:
+                        pass
+                self.process.terminate()
+                self.process.wait()
+                self.process.kill()
+                self.process = None
+        except OSError:
+            pass
+
+    def __del__(self):
+        # `subprocess.Popen` doesn't send signal on `__del__`;
+        # so we attempt to close the launched process when `__del__`
+        # is triggered.
+        try:
+            self.stop()
+        except Exception:
+            pass

+ 192 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/touch_actions.py

@@ -0,0 +1,192 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+The Touch Actions implementation
+"""
+
+from selenium.webdriver.remote.command import Command
+
+
+class TouchActions(object):
+    """
+    Generate touch actions. Works like ActionChains; actions are stored in the
+    TouchActions object and are fired with perform().
+    """
+
+    def __init__(self, driver):
+        """
+        Creates a new TouchActions object.
+
+        :Args:
+         - driver: The WebDriver instance which performs user actions.
+           It should be with touchscreen enabled.
+        """
+        self._driver = driver
+        self._actions = []
+
+    def perform(self):
+        """
+        Performs all stored actions.
+        """
+        for action in self._actions:
+            action()
+
+    def tap(self, on_element):
+        """
+        Taps on a given element.
+
+        :Args:
+         - on_element: The element to tap.
+        """
+        self._actions.append(lambda: self._driver.execute(
+            Command.SINGLE_TAP, {'element': on_element.id}))
+        return self
+
+    def double_tap(self, on_element):
+        """
+        Double taps on a given element.
+
+        :Args:
+         - on_element: The element to tap.
+        """
+        self._actions.append(lambda: self._driver.execute(
+            Command.DOUBLE_TAP, {'element': on_element.id}))
+        return self
+
+    def tap_and_hold(self, xcoord, ycoord):
+        """
+        Touch down at given coordinates.
+
+        :Args:
+         - xcoord: X Coordinate to touch down.
+         - ycoord: Y Coordinate to touch down.
+        """
+        self._actions.append(lambda: self._driver.execute(
+            Command.TOUCH_DOWN, {
+                'x': int(xcoord),
+                'y': int(ycoord)}))
+        return self
+
+    def move(self, xcoord, ycoord):
+        """
+        Move held tap to specified location.
+
+        :Args:
+         - xcoord: X Coordinate to move.
+         - ycoord: Y Coordinate to move.
+        """
+        self._actions.append(lambda: self._driver.execute(
+            Command.TOUCH_MOVE, {
+                'x': int(xcoord),
+                'y': int(ycoord)}))
+        return self
+
+    def release(self, xcoord, ycoord):
+        """
+        Release previously issued tap 'and hold' command at specified location.
+
+        :Args:
+         - xcoord: X Coordinate to release.
+         - ycoord: Y Coordinate to release.
+        """
+        self._actions.append(lambda: self._driver.execute(
+            Command.TOUCH_UP, {
+                'x': int(xcoord),
+                'y': int(ycoord)}))
+        return self
+
+    def scroll(self, xoffset, yoffset):
+        """
+        Touch and scroll, moving by xoffset and yoffset.
+
+        :Args:
+         - xoffset: X offset to scroll to.
+         - yoffset: Y offset to scroll to.
+        """
+        self._actions.append(lambda: self._driver.execute(
+            Command.TOUCH_SCROLL, {
+                'xoffset': int(xoffset),
+                'yoffset': int(yoffset)}))
+        return self
+
+    def scroll_from_element(self, on_element, xoffset, yoffset):
+        """
+        Touch and scroll starting at on_element, moving by xoffset and yoffset.
+
+        :Args:
+         - on_element: The element where scroll starts.
+         - xoffset: X offset to scroll to.
+         - yoffset: Y offset to scroll to.
+        """
+        self._actions.append(lambda: self._driver.execute(
+            Command.TOUCH_SCROLL, {
+                'element': on_element.id,
+                'xoffset': int(xoffset),
+                'yoffset': int(yoffset)}))
+        return self
+
+    def long_press(self, on_element):
+        """
+        Long press on an element.
+
+        :Args:
+         - on_element: The element to long press.
+        """
+        self._actions.append(lambda: self._driver.execute(
+            Command.LONG_PRESS, {'element': on_element.id}))
+        return self
+
+    def flick(self, xspeed, yspeed):
+        """
+        Flicks, starting anywhere on the screen.
+
+        :Args:
+         - xspeed: The X speed in pixels per second.
+         - yspeed: The Y speed in pixels per second.
+        """
+        self._actions.append(lambda: self._driver.execute(
+            Command.FLICK, {
+                'xspeed': int(xspeed),
+                'yspeed': int(yspeed)}))
+        return self
+
+    def flick_element(self, on_element, xoffset, yoffset, speed):
+        """
+        Flick starting at on_element, and moving by the xoffset and yoffset
+        with specified speed.
+
+        :Args:
+         - on_element: Flick will start at center of element.
+         - xoffset: X offset to flick to.
+         - yoffset: Y offset to flick to.
+         - speed: Pixels per second to flick.
+        """
+        self._actions.append(lambda: self._driver.execute(
+            Command.FLICK, {
+                'element': on_element.id,
+                'xoffset': int(xoffset),
+                'yoffset': int(yoffset),
+                'speed': int(speed)}))
+        return self
+
+    # Context manager so TouchActions can be used in a 'with .. as' statements.
+    def __enter__(self):
+        return self  # Return created instance of self.
+
+    def __exit__(self, _type, _value, _traceback):
+        pass  # Do nothing, does not require additional cleanup.

+ 152 - 0
selenium-3.141.0/build/lib/selenium/webdriver/common/utils.py

@@ -0,0 +1,152 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+The Utils methods.
+"""
+import socket
+from selenium.webdriver.common.keys import Keys
+
+try:
+    basestring
+except NameError:
+    # Python 3
+    basestring = str
+
+
+def free_port():
+    """
+    Determines a free port using sockets.
+    """
+    free_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    free_socket.bind(('0.0.0.0', 0))
+    free_socket.listen(5)
+    port = free_socket.getsockname()[1]
+    free_socket.close()
+    return port
+
+
+def find_connectable_ip(host, port=None):
+    """Resolve a hostname to an IP, preferring IPv4 addresses.
+
+    We prefer IPv4 so that we don't change behavior from previous IPv4-only
+    implementations, and because some drivers (e.g., FirefoxDriver) do not
+    support IPv6 connections.
+
+    If the optional port number is provided, only IPs that listen on the given
+    port are considered.
+
+    :Args:
+        - host - A hostname.
+        - port - Optional port number.
+
+    :Returns:
+        A single IP address, as a string. If any IPv4 address is found, one is
+        returned. Otherwise, if any IPv6 address is found, one is returned. If
+        neither, then None is returned.
+
+    """
+    try:
+        addrinfos = socket.getaddrinfo(host, None)
+    except socket.gaierror:
+        return None
+
+    ip = None
+    for family, _, _, _, sockaddr in addrinfos:
+        connectable = True
+        if port:
+            connectable = is_connectable(port, sockaddr[0])
+
+        if connectable and family == socket.AF_INET:
+            return sockaddr[0]
+        if connectable and not ip and family == socket.AF_INET6:
+            ip = sockaddr[0]
+    return ip
+
+
+def join_host_port(host, port):
+    """Joins a hostname and port together.
+
+    This is a minimal implementation intended to cope with IPv6 literals. For
+    example, _join_host_port('::1', 80) == '[::1]:80'.
+
+    :Args:
+        - host - A hostname.
+        - port - An integer port.
+
+    """
+    if ':' in host and not host.startswith('['):
+        return '[%s]:%d' % (host, port)
+    return '%s:%d' % (host, port)
+
+
+def is_connectable(port, host="localhost"):
+    """
+    Tries to connect to the server at port to see if it is running.
+
+    :Args:
+     - port - The port to connect.
+    """
+    socket_ = None
+    try:
+        socket_ = socket.create_connection((host, port), 1)
+        result = True
+    except socket.error:
+        result = False
+    finally:
+        if socket_:
+            socket_.close()
+    return result
+
+
+def is_url_connectable(port):
+    """
+    Tries to connect to the HTTP server at /status path
+    and specified port to see if it responds successfully.
+
+    :Args:
+     - port - The port to connect.
+    """
+    try:
+        from urllib import request as url_request
+    except ImportError:
+        import urllib2 as url_request
+
+    try:
+        res = url_request.urlopen("http://127.0.0.1:%s/status" % port)
+        if res.getcode() == 200:
+            return True
+        else:
+            return False
+    except Exception:
+        return False
+
+
+def keys_to_typing(value):
+    """Processes the values that will be typed in the element."""
+    typing = []
+    for val in value:
+        if isinstance(val, Keys):
+            typing.append(val)
+        elif isinstance(val, int):
+            val = str(val)
+            for i in range(len(val)):
+                typing.append(val[i])
+        else:
+            for i in range(len(val)):
+                typing.append(val[i])
+    return typing

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/edge/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 54 - 0
selenium-3.141.0/build/lib/selenium/webdriver/edge/options.py

@@ -0,0 +1,54 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+
+
+class Options(object):
+
+    def __init__(self):
+        self._page_load_strategy = "normal"
+        self._caps = DesiredCapabilities.EDGE.copy()
+
+    @property
+    def page_load_strategy(self):
+        return self._page_load_strategy
+
+    @page_load_strategy.setter
+    def page_load_strategy(self, value):
+        if value not in ['normal', 'eager', 'none']:
+            raise ValueError("Page Load Strategy should be 'normal', 'eager' or 'none'.")
+        self._page_load_strategy = value
+
+    @property
+    def capabilities(self):
+        return self._caps
+
+    def set_capability(self, name, value):
+        """Sets a capability."""
+        self._caps[name] = value
+
+    def to_capabilities(self):
+        """
+            Creates a capabilities with all the options that have been set and
+
+            returns a dictionary with everything
+        """
+        caps = self._caps
+        caps['pageLoadStrategy'] = self._page_load_strategy
+
+        return caps

+ 57 - 0
selenium-3.141.0/build/lib/selenium/webdriver/edge/service.py

@@ -0,0 +1,57 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.common import service
+
+
+class Service(service.Service):
+
+    def __init__(self, executable_path, port=0, verbose=False, log_path=None):
+        """
+        Creates a new instance of the EdgeDriver service.
+
+        EdgeDriver provides an interface for Microsoft WebDriver to use
+        with Microsoft Edge.
+
+        :param executable_path: Path to the Microsoft WebDriver binary.
+        :param port: Run the remote service on a specified port.
+            Defaults to 0, which binds to a random open port of the
+            system's choosing.
+        :verbose: Whether to make the webdriver more verbose (passes the
+            --verbose option to the binary). Defaults to False.
+        :param log_path: Optional path for the webdriver binary to log to.
+            Defaults to None which disables logging.
+
+        """
+
+        self.service_args = []
+        if verbose:
+            self.service_args.append("--verbose")
+
+        params = {
+            "executable": executable_path,
+            "port": port,
+            "start_error_message": "Please download from http://go.microsoft.com/fwlink/?LinkId=619687"
+        }
+
+        if log_path:
+            params["log_file"] = open(log_path, "a+")
+
+        service.Service.__init__(self, **params)
+
+    def command_line_args(self):
+        return ["--port=%d" % self.port] + self.service_args

+ 71 - 0
selenium-3.141.0/build/lib/selenium/webdriver/edge/webdriver.py

@@ -0,0 +1,71 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import warnings
+
+from selenium.webdriver.common import utils
+from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
+from selenium.webdriver.remote.remote_connection import RemoteConnection
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+from .service import Service
+
+
+class WebDriver(RemoteWebDriver):
+
+    def __init__(self, executable_path='MicrosoftWebDriver.exe',
+                 capabilities=None, port=0, verbose=False, service_log_path=None,
+                 log_path=None, keep_alive=False):
+        """
+        Creates a new instance of the chrome driver.
+
+        Starts the service and then creates new instance of chrome driver.
+
+        :Args:
+         - executable_path - path to the executable. If the default is used it assumes the executable is in the $PATH
+         - capabilities - Dictionary object with non-browser specific
+           capabilities only, such as "proxy" or "loggingPref".
+         - port - port you would like the service to run, if left as 0, a free port will be found.
+         - verbose - whether to set verbose logging in the service
+         - service_log_path - Where to log information from the driver.
+         - log_path: Deprecated argument for service_log_path
+         - keep_alive - Whether to configure ChromeRemoteConnection to use HTTP keep-alive.
+         """
+        if log_path:
+            warnings.warn('use service_log_path instead of log_path',
+                          DeprecationWarning, stacklevel=2)
+            service_log_path = log_path
+
+        self.port = port
+        if self.port == 0:
+            self.port = utils.free_port()
+
+        self.edge_service = Service(executable_path, port=self.port, verbose=verbose, log_path=service_log_path)
+        self.edge_service.start()
+
+        if capabilities is None:
+            capabilities = DesiredCapabilities.EDGE
+
+        RemoteWebDriver.__init__(
+            self,
+            command_executor=RemoteConnection('http://localhost:%d' % self.port,
+                                              resolve_ip=False,
+                                              keep_alive=keep_alive),
+            desired_capabilities=capabilities)
+        self._is_remote = False
+
+    def quit(self):
+        RemoteWebDriver.quit(self)
+        self.edge_service.stop()

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/firefox/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

二进制
selenium-3.141.0/build/lib/selenium/webdriver/firefox/amd64/x_ignore_nofocus.so


+ 84 - 0
selenium-3.141.0/build/lib/selenium/webdriver/firefox/extension_connection.py

@@ -0,0 +1,84 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import logging
+import time
+
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+from selenium.webdriver.common import utils
+from selenium.webdriver.remote.command import Command
+from selenium.webdriver.remote.remote_connection import RemoteConnection
+from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
+
+LOGGER = logging.getLogger(__name__)
+PORT = 0
+HOST = None
+_URL = ""
+
+
+class ExtensionConnection(RemoteConnection):
+    def __init__(self, host, firefox_profile, firefox_binary=None, timeout=30):
+        self.profile = firefox_profile
+        self.binary = firefox_binary
+        HOST = host
+        timeout = int(timeout)
+
+        if self.binary is None:
+            self.binary = FirefoxBinary()
+
+        if HOST is None:
+            HOST = "127.0.0.1"
+
+        PORT = utils.free_port()
+        self.profile.port = PORT
+        self.profile.update_preferences()
+
+        self.profile.add_extension()
+
+        self.binary.launch_browser(self.profile, timeout=timeout)
+        _URL = "http://%s:%d/hub" % (HOST, PORT)
+        RemoteConnection.__init__(
+            self, _URL, keep_alive=True)
+
+    def quit(self, sessionId=None):
+        self.execute(Command.QUIT, {'sessionId': sessionId})
+        while self.is_connectable():
+            LOGGER.info("waiting to quit")
+            time.sleep(1)
+
+    def connect(self):
+        """Connects to the extension and retrieves the session id."""
+        return self.execute(Command.NEW_SESSION,
+                            {'desiredCapabilities': DesiredCapabilities.FIREFOX})
+
+    @classmethod
+    def connect_and_quit(self):
+        """Connects to an running browser and quit immediately."""
+        self._request('%s/extensions/firefox/quit' % _URL)
+
+    @classmethod
+    def is_connectable(self):
+        """Trys to connect to the extension but do not retrieve context."""
+        utils.is_connectable(self.profile.port)
+
+
+class ExtensionConnectionError(Exception):
+    """An internal error occurred int the extension.
+
+    Might be caused by bad input or bugs in webdriver
+    """
+    pass

+ 217 - 0
selenium-3.141.0/build/lib/selenium/webdriver/firefox/firefox_binary.py

@@ -0,0 +1,217 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+import os
+import platform
+from subprocess import Popen, STDOUT
+from selenium.common.exceptions import WebDriverException
+from selenium.webdriver.common import utils
+import time
+
+
+class FirefoxBinary(object):
+
+    NO_FOCUS_LIBRARY_NAME = "x_ignore_nofocus.so"
+
+    def __init__(self, firefox_path=None, log_file=None):
+        """
+        Creates a new instance of Firefox binary.
+
+        :Args:
+         - firefox_path - Path to the Firefox executable. By default, it will be detected from the standard locations.
+         - log_file - A file object to redirect the firefox process output to. It can be sys.stdout.
+                      Please note that with parallel run the output won't be synchronous.
+                      By default, it will be redirected to /dev/null.
+        """
+        self._start_cmd = firefox_path
+        # We used to default to subprocess.PIPE instead of /dev/null, but after
+        # a while the pipe would fill up and Firefox would freeze.
+        self._log_file = log_file or open(os.devnull, "wb")
+        self.command_line = None
+        if self._start_cmd is None:
+            self._start_cmd = self._get_firefox_start_cmd()
+        if not self._start_cmd.strip():
+            raise WebDriverException(
+                "Failed to find firefox binary. You can set it by specifying "
+                "the path to 'firefox_binary':\n\nfrom "
+                "selenium.webdriver.firefox.firefox_binary import "
+                "FirefoxBinary\n\nbinary = "
+                "FirefoxBinary('/path/to/binary')\ndriver = "
+                "webdriver.Firefox(firefox_binary=binary)")
+        # Rather than modifying the environment of the calling Python process
+        # copy it and modify as needed.
+        self._firefox_env = os.environ.copy()
+        self._firefox_env["MOZ_CRASHREPORTER_DISABLE"] = "1"
+        self._firefox_env["MOZ_NO_REMOTE"] = "1"
+        self._firefox_env["NO_EM_RESTART"] = "1"
+
+    def add_command_line_options(self, *args):
+        self.command_line = args
+
+    def launch_browser(self, profile, timeout=30):
+        """Launches the browser for the given profile name.
+        It is assumed the profile already exists.
+        """
+        self.profile = profile
+
+        self._start_from_profile_path(self.profile.path)
+        self._wait_until_connectable(timeout=timeout)
+
+    def kill(self):
+        """Kill the browser.
+
+        This is useful when the browser is stuck.
+        """
+        if self.process:
+            self.process.kill()
+            self.process.wait()
+
+    def _start_from_profile_path(self, path):
+        self._firefox_env["XRE_PROFILE_PATH"] = path
+
+        if platform.system().lower() == 'linux':
+            self._modify_link_library_path()
+        command = [self._start_cmd, "-foreground"]
+        if self.command_line is not None:
+            for cli in self.command_line:
+                command.append(cli)
+        self.process = Popen(
+            command, stdout=self._log_file, stderr=STDOUT,
+            env=self._firefox_env)
+
+    def _wait_until_connectable(self, timeout=30):
+        """Blocks until the extension is connectable in the firefox."""
+        count = 0
+        while not utils.is_connectable(self.profile.port):
+            if self.process.poll() is not None:
+                # Browser has exited
+                raise WebDriverException(
+                    "The browser appears to have exited "
+                    "before we could connect. If you specified a log_file in "
+                    "the FirefoxBinary constructor, check it for details.")
+            if count >= timeout:
+                self.kill()
+                raise WebDriverException(
+                    "Can't load the profile. Possible firefox version mismatch. "
+                    "You must use GeckoDriver instead for Firefox 48+. Profile "
+                    "Dir: %s If you specified a log_file in the "
+                    "FirefoxBinary constructor, check it for details."
+                    % (self.profile.path))
+            count += 1
+            time.sleep(1)
+        return True
+
+    def _find_exe_in_registry(self):
+        try:
+            from _winreg import OpenKey, QueryValue, HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER
+        except ImportError:
+            from winreg import OpenKey, QueryValue, HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER
+        import shlex
+        keys = (r"SOFTWARE\Classes\FirefoxHTML\shell\open\command",
+                r"SOFTWARE\Classes\Applications\firefox.exe\shell\open\command")
+        command = ""
+        for path in keys:
+            try:
+                key = OpenKey(HKEY_LOCAL_MACHINE, path)
+                command = QueryValue(key, "")
+                break
+            except OSError:
+                try:
+                    key = OpenKey(HKEY_CURRENT_USER, path)
+                    command = QueryValue(key, "")
+                    break
+                except OSError:
+                    pass
+        else:
+            return ""
+
+        if not command:
+            return ""
+
+        return shlex.split(command)[0]
+
+    def _get_firefox_start_cmd(self):
+        """Return the command to start firefox."""
+        start_cmd = ""
+        if platform.system() == "Darwin":
+            start_cmd = "/Applications/Firefox.app/Contents/MacOS/firefox-bin"
+            # fallback to homebrew installation for mac users
+            if not os.path.exists(start_cmd):
+                start_cmd = os.path.expanduser("~") + start_cmd
+        elif platform.system() == "Windows":
+            start_cmd = (self._find_exe_in_registry() or self._default_windows_location())
+        elif platform.system() == 'Java' and os._name == 'nt':
+            start_cmd = self._default_windows_location()
+        else:
+            for ffname in ["firefox", "iceweasel"]:
+                start_cmd = self.which(ffname)
+                if start_cmd is not None:
+                    break
+            else:
+                # couldn't find firefox on the system path
+                raise RuntimeError(
+                    "Could not find firefox in your system PATH." +
+                    " Please specify the firefox binary location or install firefox")
+        return start_cmd
+
+    def _default_windows_location(self):
+        program_files = [os.getenv("PROGRAMFILES", r"C:\Program Files"),
+                         os.getenv("PROGRAMFILES(X86)", r"C:\Program Files (x86)")]
+        for path in program_files:
+            binary_path = os.path.join(path, r"Mozilla Firefox\firefox.exe")
+            if os.access(binary_path, os.X_OK):
+                return binary_path
+        return ""
+
+    def _modify_link_library_path(self):
+        existing_ld_lib_path = os.environ.get('LD_LIBRARY_PATH', '')
+
+        new_ld_lib_path = self._extract_and_check(
+            self.profile, self.NO_FOCUS_LIBRARY_NAME, "x86", "amd64")
+
+        new_ld_lib_path += existing_ld_lib_path
+
+        self._firefox_env["LD_LIBRARY_PATH"] = new_ld_lib_path
+        self._firefox_env['LD_PRELOAD'] = self.NO_FOCUS_LIBRARY_NAME
+
+    def _extract_and_check(self, profile, no_focus_so_name, x86, amd64):
+
+        paths = [x86, amd64]
+        built_path = ""
+        for path in paths:
+            library_path = os.path.join(profile.path, path)
+            if not os.path.exists(library_path):
+                os.makedirs(library_path)
+            import shutil
+            shutil.copy(os.path.join(
+                os.path.dirname(__file__),
+                path,
+                self.NO_FOCUS_LIBRARY_NAME),
+                library_path)
+            built_path += library_path + ":"
+
+        return built_path
+
+    def which(self, fname):
+        """Returns the fully qualified path by searching Path of the given
+        name"""
+        for pe in os.environ['PATH'].split(os.pathsep):
+            checkname = os.path.join(pe, fname)
+            if os.access(checkname, os.X_OK) and not os.path.isdir(checkname):
+                return checkname
+        return None

+ 408 - 0
selenium-3.141.0/build/lib/selenium/webdriver/firefox/firefox_profile.py

@@ -0,0 +1,408 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from __future__ import with_statement
+
+import base64
+import copy
+import json
+import os
+import re
+import shutil
+import sys
+import tempfile
+import zipfile
+
+try:
+    from cStringIO import StringIO as BytesIO
+except ImportError:
+    from io import BytesIO
+
+from xml.dom import minidom
+from selenium.webdriver.common.proxy import ProxyType
+from selenium.common.exceptions import WebDriverException
+
+
+WEBDRIVER_EXT = "webdriver.xpi"
+WEBDRIVER_PREFERENCES = "webdriver_prefs.json"
+EXTENSION_NAME = "fxdriver@googlecode.com"
+
+
+class AddonFormatError(Exception):
+    """Exception for not well-formed add-on manifest files"""
+
+
+class FirefoxProfile(object):
+    ANONYMOUS_PROFILE_NAME = "WEBDRIVER_ANONYMOUS_PROFILE"
+    DEFAULT_PREFERENCES = None
+
+    def __init__(self, profile_directory=None):
+        """
+        Initialises a new instance of a Firefox Profile
+
+        :args:
+         - profile_directory: Directory of profile that you want to use. If a
+           directory is passed in it will be cloned and the cloned directory
+           will be used by the driver when instantiated.
+           This defaults to None and will create a new
+           directory when object is created.
+        """
+        if not FirefoxProfile.DEFAULT_PREFERENCES:
+            with open(os.path.join(os.path.dirname(__file__),
+                                   WEBDRIVER_PREFERENCES)) as default_prefs:
+                FirefoxProfile.DEFAULT_PREFERENCES = json.load(default_prefs)
+
+        self.default_preferences = copy.deepcopy(
+            FirefoxProfile.DEFAULT_PREFERENCES['mutable'])
+        self.native_events_enabled = True
+        self.profile_dir = profile_directory
+        self.tempfolder = None
+        if self.profile_dir is None:
+            self.profile_dir = self._create_tempfolder()
+        else:
+            self.tempfolder = tempfile.mkdtemp()
+            newprof = os.path.join(self.tempfolder, "webdriver-py-profilecopy")
+            shutil.copytree(self.profile_dir, newprof,
+                            ignore=shutil.ignore_patterns("parent.lock", "lock", ".parentlock"))
+            self.profile_dir = newprof
+            os.chmod(self.profile_dir, 0o755)
+            self._read_existing_userjs(os.path.join(self.profile_dir, "user.js"))
+        self.extensionsDir = os.path.join(self.profile_dir, "extensions")
+        self.userPrefs = os.path.join(self.profile_dir, "user.js")
+        if os.path.isfile(self.userPrefs):
+            os.chmod(self.userPrefs, 0o644)
+
+    # Public Methods
+    def set_preference(self, key, value):
+        """
+        sets the preference that we want in the profile.
+        """
+        self.default_preferences[key] = value
+
+    def add_extension(self, extension=WEBDRIVER_EXT):
+        self._install_extension(extension)
+
+    def update_preferences(self):
+        for key, value in FirefoxProfile.DEFAULT_PREFERENCES['frozen'].items():
+            self.default_preferences[key] = value
+        self._write_user_prefs(self.default_preferences)
+
+    # Properties
+
+    @property
+    def path(self):
+        """
+        Gets the profile directory that is currently being used
+        """
+        return self.profile_dir
+
+    @property
+    def port(self):
+        """
+        Gets the port that WebDriver is working on
+        """
+        return self._port
+
+    @port.setter
+    def port(self, port):
+        """
+        Sets the port that WebDriver will be running on
+        """
+        if not isinstance(port, int):
+            raise WebDriverException("Port needs to be an integer")
+        try:
+            port = int(port)
+            if port < 1 or port > 65535:
+                raise WebDriverException("Port number must be in the range 1..65535")
+        except (ValueError, TypeError):
+            raise WebDriverException("Port needs to be an integer")
+        self._port = port
+        self.set_preference("webdriver_firefox_port", self._port)
+
+    @property
+    def accept_untrusted_certs(self):
+        return self.default_preferences["webdriver_accept_untrusted_certs"]
+
+    @accept_untrusted_certs.setter
+    def accept_untrusted_certs(self, value):
+        if value not in [True, False]:
+            raise WebDriverException("Please pass in a Boolean to this call")
+        self.set_preference("webdriver_accept_untrusted_certs", value)
+
+    @property
+    def assume_untrusted_cert_issuer(self):
+        return self.default_preferences["webdriver_assume_untrusted_issuer"]
+
+    @assume_untrusted_cert_issuer.setter
+    def assume_untrusted_cert_issuer(self, value):
+        if value not in [True, False]:
+            raise WebDriverException("Please pass in a Boolean to this call")
+
+        self.set_preference("webdriver_assume_untrusted_issuer", value)
+
+    @property
+    def native_events_enabled(self):
+        return self.default_preferences['webdriver_enable_native_events']
+
+    @native_events_enabled.setter
+    def native_events_enabled(self, value):
+        if value not in [True, False]:
+            raise WebDriverException("Please pass in a Boolean to this call")
+        self.set_preference("webdriver_enable_native_events", value)
+
+    @property
+    def encoded(self):
+        """
+        A zipped, base64 encoded string of profile directory
+        for use with remote WebDriver JSON wire protocol
+        """
+        self.update_preferences()
+        fp = BytesIO()
+        zipped = zipfile.ZipFile(fp, 'w', zipfile.ZIP_DEFLATED)
+        path_root = len(self.path) + 1  # account for trailing slash
+        for base, dirs, files in os.walk(self.path):
+            for fyle in files:
+                filename = os.path.join(base, fyle)
+                zipped.write(filename, filename[path_root:])
+        zipped.close()
+        return base64.b64encode(fp.getvalue()).decode('UTF-8')
+
+    def set_proxy(self, proxy):
+        import warnings
+
+        warnings.warn(
+            "This method has been deprecated. Please pass in the proxy object to the Driver Object",
+            DeprecationWarning, stacklevel=2)
+        if proxy is None:
+            raise ValueError("proxy can not be None")
+
+        if proxy.proxy_type is ProxyType.UNSPECIFIED:
+            return
+
+        self.set_preference("network.proxy.type", proxy.proxy_type['ff_value'])
+
+        if proxy.proxy_type is ProxyType.MANUAL:
+            self.set_preference("network.proxy.no_proxies_on", proxy.no_proxy)
+            self._set_manual_proxy_preference("ftp", proxy.ftp_proxy)
+            self._set_manual_proxy_preference("http", proxy.http_proxy)
+            self._set_manual_proxy_preference("ssl", proxy.ssl_proxy)
+            self._set_manual_proxy_preference("socks", proxy.socks_proxy)
+        elif proxy.proxy_type is ProxyType.PAC:
+            self.set_preference("network.proxy.autoconfig_url", proxy.proxy_autoconfig_url)
+
+    def _set_manual_proxy_preference(self, key, setting):
+        if setting is None or setting is '':
+            return
+
+        host_details = setting.split(":")
+        self.set_preference("network.proxy.%s" % key, host_details[0])
+        if len(host_details) > 1:
+            self.set_preference("network.proxy.%s_port" % key, int(host_details[1]))
+
+    def _create_tempfolder(self):
+        """
+        Creates a temp folder to store User.js and the extension
+        """
+        return tempfile.mkdtemp()
+
+    def _write_user_prefs(self, user_prefs):
+        """
+        writes the current user prefs dictionary to disk
+        """
+        with open(self.userPrefs, "w") as f:
+            for key, value in user_prefs.items():
+                f.write('user_pref("%s", %s);\n' % (key, json.dumps(value)))
+
+    def _read_existing_userjs(self, userjs):
+        import warnings
+
+        PREF_RE = re.compile(r'user_pref\("(.*)",\s(.*)\)')
+        try:
+            with open(userjs) as f:
+                for usr in f:
+                    matches = re.search(PREF_RE, usr)
+                    try:
+                        self.default_preferences[matches.group(1)] = json.loads(matches.group(2))
+                    except Exception:
+                        warnings.warn("(skipping) failed to json.loads existing preference: " +
+                                      matches.group(1) + matches.group(2))
+        except Exception:
+            # The profile given hasn't had any changes made, i.e no users.js
+            pass
+
+    def _install_extension(self, addon, unpack=True):
+        """
+            Installs addon from a filepath, url
+            or directory of addons in the profile.
+            - path: url, absolute path to .xpi, or directory of addons
+            - unpack: whether to unpack unless specified otherwise in the install.rdf
+        """
+        if addon == WEBDRIVER_EXT:
+            addon = os.path.join(os.path.dirname(__file__), WEBDRIVER_EXT)
+
+        tmpdir = None
+        xpifile = None
+        if addon.endswith('.xpi'):
+            tmpdir = tempfile.mkdtemp(suffix='.' + os.path.split(addon)[-1])
+            compressed_file = zipfile.ZipFile(addon, 'r')
+            for name in compressed_file.namelist():
+                if name.endswith('/'):
+                    if not os.path.isdir(os.path.join(tmpdir, name)):
+                        os.makedirs(os.path.join(tmpdir, name))
+                else:
+                    if not os.path.isdir(os.path.dirname(os.path.join(tmpdir, name))):
+                        os.makedirs(os.path.dirname(os.path.join(tmpdir, name)))
+                    data = compressed_file.read(name)
+                    with open(os.path.join(tmpdir, name), 'wb') as f:
+                        f.write(data)
+            xpifile = addon
+            addon = tmpdir
+
+        # determine the addon id
+        addon_details = self._addon_details(addon)
+        addon_id = addon_details.get('id')
+        assert addon_id, 'The addon id could not be found: %s' % addon
+
+        # copy the addon to the profile
+        addon_path = os.path.join(self.extensionsDir, addon_id)
+        if not unpack and not addon_details['unpack'] and xpifile:
+            if not os.path.exists(self.extensionsDir):
+                os.makedirs(self.extensionsDir)
+                os.chmod(self.extensionsDir, 0o755)
+            shutil.copy(xpifile, addon_path + '.xpi')
+        else:
+            if not os.path.exists(addon_path):
+                shutil.copytree(addon, addon_path, symlinks=True)
+
+        # remove the temporary directory, if any
+        if tmpdir:
+            shutil.rmtree(tmpdir)
+
+    def _addon_details(self, addon_path):
+        """
+        Returns a dictionary of details about the addon.
+
+        :param addon_path: path to the add-on directory or XPI
+
+        Returns::
+
+            {'id':      u'rainbow@colors.org', # id of the addon
+             'version': u'1.4',                # version of the addon
+             'name':    u'Rainbow',            # name of the addon
+             'unpack':  False }                # whether to unpack the addon
+        """
+
+        details = {
+            'id': None,
+            'unpack': False,
+            'name': None,
+            'version': None
+        }
+
+        def get_namespace_id(doc, url):
+            attributes = doc.documentElement.attributes
+            namespace = ""
+            for i in range(attributes.length):
+                if attributes.item(i).value == url:
+                    if ":" in attributes.item(i).name:
+                        # If the namespace is not the default one remove 'xlmns:'
+                        namespace = attributes.item(i).name.split(':')[1] + ":"
+                        break
+            return namespace
+
+        def get_text(element):
+            """Retrieve the text value of a given node"""
+            rc = []
+            for node in element.childNodes:
+                if node.nodeType == node.TEXT_NODE:
+                    rc.append(node.data)
+            return ''.join(rc).strip()
+
+        def parse_manifest_json(content):
+            """Extracts the details from the contents of a WebExtensions `manifest.json` file."""
+            manifest = json.loads(content)
+            try:
+                id = manifest['applications']['gecko']['id']
+            except KeyError:
+                id = manifest['name'].replace(" ", "") + "@" + manifest['version']
+            return {
+                'id': id,
+                'version': manifest['version'],
+                'name': manifest['version'],
+                'unpack': False,
+            }
+
+        if not os.path.exists(addon_path):
+            raise IOError('Add-on path does not exist: %s' % addon_path)
+
+        try:
+            if zipfile.is_zipfile(addon_path):
+                # Bug 944361 - We cannot use 'with' together with zipFile because
+                # it will cause an exception thrown in Python 2.6.
+                try:
+                    compressed_file = zipfile.ZipFile(addon_path, 'r')
+                    if 'manifest.json' in compressed_file.namelist():
+                        return parse_manifest_json(compressed_file.read('manifest.json'))
+
+                    manifest = compressed_file.read('install.rdf')
+                finally:
+                    compressed_file.close()
+            elif os.path.isdir(addon_path):
+                manifest_json_filename = os.path.join(addon_path, 'manifest.json')
+                if os.path.exists(manifest_json_filename):
+                    with open(manifest_json_filename, 'r') as f:
+                        return parse_manifest_json(f.read())
+
+                with open(os.path.join(addon_path, 'install.rdf'), 'r') as f:
+                    manifest = f.read()
+            else:
+                raise IOError('Add-on path is neither an XPI nor a directory: %s' % addon_path)
+        except (IOError, KeyError) as e:
+            raise AddonFormatError(str(e), sys.exc_info()[2])
+
+        try:
+            doc = minidom.parseString(manifest)
+
+            # Get the namespaces abbreviations
+            em = get_namespace_id(doc, 'http://www.mozilla.org/2004/em-rdf#')
+            rdf = get_namespace_id(doc, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#')
+
+            description = doc.getElementsByTagName(rdf + 'Description').item(0)
+            if description is None:
+                description = doc.getElementsByTagName('Description').item(0)
+            for node in description.childNodes:
+                # Remove the namespace prefix from the tag for comparison
+                entry = node.nodeName.replace(em, "")
+                if entry in details.keys():
+                    details.update({entry: get_text(node)})
+            if details.get('id') is None:
+                for i in range(description.attributes.length):
+                    attribute = description.attributes.item(i)
+                    if attribute.name == em + 'id':
+                        details.update({'id': attribute.value})
+        except Exception as e:
+            raise AddonFormatError(str(e), sys.exc_info()[2])
+
+        # turn unpack into a true/false value
+        if isinstance(details['unpack'], str):
+            details['unpack'] = details['unpack'].lower() == 'true'
+
+        # If no ID is set, the add-on is invalid
+        if details.get('id') is None:
+            raise AddonFormatError('Add-on id could not be found.')
+
+        return details

+ 189 - 0
selenium-3.141.0/build/lib/selenium/webdriver/firefox/options.py

@@ -0,0 +1,189 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import warnings
+
+from selenium.common.exceptions import InvalidArgumentException
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+from selenium.webdriver.common.proxy import Proxy
+from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
+from selenium.webdriver.firefox.firefox_profile import FirefoxProfile
+
+
+class Log(object):
+    def __init__(self):
+        self.level = None
+
+    def to_capabilities(self):
+        if self.level is not None:
+            return {"log": {"level": self.level}}
+        return {}
+
+
+class Options(object):
+    KEY = "moz:firefoxOptions"
+
+    def __init__(self):
+        self._binary = None
+        self._preferences = {}
+        self._profile = None
+        self._proxy = None
+        self._caps = DesiredCapabilities.FIREFOX.copy()
+        self._arguments = []
+        self.log = Log()
+
+    @property
+    def binary(self):
+        """Returns the FirefoxBinary instance"""
+        return self._binary
+
+    @binary.setter
+    def binary(self, new_binary):
+        """Sets location of the browser binary, either by string or
+        ``FirefoxBinary`` instance.
+
+        """
+        if not isinstance(new_binary, FirefoxBinary):
+            new_binary = FirefoxBinary(new_binary)
+        self._binary = new_binary
+
+    @property
+    def binary_location(self):
+        """Returns the location of the binary."""
+        return self.binary._start_cmd
+
+    @binary_location.setter  # noqa
+    def binary_location(self, value):
+        """ Sets the location of the browser binary by string """
+        self.binary = value
+
+    @property
+    def accept_insecure_certs(self):
+        return self._caps.get('acceptInsecureCerts')
+
+    @accept_insecure_certs.setter
+    def accept_insecure_certs(self, value):
+        self._caps['acceptInsecureCerts'] = value
+
+    @property
+    def capabilities(self):
+        return self._caps
+
+    def set_capability(self, name, value):
+        """Sets a capability."""
+        self._caps[name] = value
+
+    @property
+    def preferences(self):
+        """Returns a dict of preferences."""
+        return self._preferences
+
+    def set_preference(self, name, value):
+        """Sets a preference."""
+        self._preferences[name] = value
+
+    @property
+    def proxy(self):
+        """ returns Proxy if set otherwise None."""
+        return self._proxy
+
+    @proxy.setter
+    def proxy(self, value):
+        if not isinstance(value, Proxy):
+            raise InvalidArgumentException("Only Proxy objects can be passed in.")
+        self._proxy = value
+
+    @property
+    def profile(self):
+        """Returns the Firefox profile to use."""
+        return self._profile
+
+    @profile.setter
+    def profile(self, new_profile):
+        """Sets location of the browser profile to use, either by string
+        or ``FirefoxProfile``.
+
+        """
+        if not isinstance(new_profile, FirefoxProfile):
+            new_profile = FirefoxProfile(new_profile)
+        self._profile = new_profile
+
+    @property
+    def arguments(self):
+        """Returns a list of browser process arguments."""
+        return self._arguments
+
+    def add_argument(self, argument):
+        """Add argument to be used for the browser process."""
+        if argument is None:
+            raise ValueError()
+        self._arguments.append(argument)
+
+    @property
+    def headless(self):
+        """
+        Returns whether or not the headless argument is set
+        """
+        return '-headless' in self._arguments
+
+    @headless.setter
+    def headless(self, value):
+        """
+        Sets the headless argument
+
+        Args:
+          value: boolean value indicating to set the headless option
+        """
+        if value is True:
+            self._arguments.append('-headless')
+        elif '-headless' in self._arguments:
+            self._arguments.remove('-headless')
+
+    def set_headless(self, headless=True):
+        """ Deprecated, options.headless = True """
+        warnings.warn('use setter for headless property instead of set_headless',
+                      DeprecationWarning, stacklevel=2)
+        self.headless = headless
+
+    def to_capabilities(self):
+        """Marshals the Firefox options to a `moz:firefoxOptions`
+        object.
+
+        """
+        # This intentionally looks at the internal properties
+        # so if a binary or profile has _not_ been set,
+        # it will defer to geckodriver to find the system Firefox
+        # and generate a fresh profile.
+        caps = self._caps
+        opts = {}
+
+        if self._binary is not None:
+            opts["binary"] = self._binary._start_cmd
+        if len(self._preferences) > 0:
+            opts["prefs"] = self._preferences
+        if self._proxy is not None:
+            self._proxy.add_to_capabilities(opts)
+        if self._profile is not None:
+            opts["profile"] = self._profile.encoded
+        if len(self._arguments) > 0:
+            opts["args"] = self._arguments
+
+        opts.update(self.log.to_capabilities())
+
+        if len(opts) > 0:
+            caps[Options.KEY] = opts
+
+        return caps

+ 34 - 0
selenium-3.141.0/build/lib/selenium/webdriver/firefox/remote_connection.py

@@ -0,0 +1,34 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.remote.remote_connection import RemoteConnection
+
+
+class FirefoxRemoteConnection(RemoteConnection):
+    def __init__(self, remote_server_addr, keep_alive=True):
+        RemoteConnection.__init__(self, remote_server_addr, keep_alive)
+
+        self._commands["GET_CONTEXT"] = ('GET', '/session/$sessionId/moz/context')
+        self._commands["SET_CONTEXT"] = ("POST", "/session/$sessionId/moz/context")
+        self._commands["ELEMENT_GET_ANONYMOUS_CHILDREN"] = \
+            ("POST", "/session/$sessionId/moz/xbl/$id/anonymous_children")
+        self._commands["ELEMENT_FIND_ANONYMOUS_ELEMENTS_BY_ATTRIBUTE"] = \
+            ("POST", "/session/$sessionId/moz/xbl/$id/anonymous_by_attribute")
+        self._commands["INSTALL_ADDON"] = \
+            ("POST", "/session/$sessionId/moz/addon/install")
+        self._commands["UNINSTALL_ADDON"] = \
+            ("POST", "/session/$sessionId/moz/addon/uninstall")

+ 54 - 0
selenium-3.141.0/build/lib/selenium/webdriver/firefox/service.py

@@ -0,0 +1,54 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.common import service
+
+
+class Service(service.Service):
+    """Object that manages the starting and stopping of the
+    GeckoDriver."""
+
+    def __init__(self, executable_path, port=0, service_args=None,
+                 log_path="geckodriver.log", env=None):
+        """Creates a new instance of the GeckoDriver remote service proxy.
+
+        GeckoDriver provides a HTTP interface speaking the W3C WebDriver
+        protocol to Marionette.
+
+        :param executable_path: Path to the GeckoDriver binary.
+        :param port: Run the remote service on a specified port.
+            Defaults to 0, which binds to a random open port of the
+            system's choosing.
+        :param service_args: Optional list of arguments to pass to the
+            GeckoDriver binary.
+        :param log_path: Optional path for the GeckoDriver to log to.
+            Defaults to _geckodriver.log_ in the current working directory.
+        :param env: Optional dictionary of output variables to expose
+            in the services' environment.
+
+        """
+        log_file = open(log_path, "a+") if log_path is not None and log_path != "" else None
+
+        service.Service.__init__(
+            self, executable_path, port=port, log_file=log_file, env=env)
+        self.service_args = service_args or []
+
+    def command_line_args(self):
+        return ["--port", "%d" % self.port] + self.service_args
+
+    def send_remote_shutdown_command(self):
+        pass

+ 276 - 0
selenium-3.141.0/build/lib/selenium/webdriver/firefox/webdriver.py

@@ -0,0 +1,276 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import warnings
+
+try:
+    basestring
+except NameError:  # Python 3.x
+    basestring = str
+
+import shutil
+import sys
+from contextlib import contextmanager
+
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
+
+from .extension_connection import ExtensionConnection
+from .firefox_binary import FirefoxBinary
+from .firefox_profile import FirefoxProfile
+from .options import Options
+from .remote_connection import FirefoxRemoteConnection
+from .service import Service
+from .webelement import FirefoxWebElement
+
+
+class WebDriver(RemoteWebDriver):
+
+    # There is no native event support on Mac
+    NATIVE_EVENTS_ALLOWED = sys.platform != "darwin"
+
+    CONTEXT_CHROME = "chrome"
+    CONTEXT_CONTENT = "content"
+
+    _web_element_cls = FirefoxWebElement
+
+    def __init__(self, firefox_profile=None, firefox_binary=None,
+                 timeout=30, capabilities=None, proxy=None,
+                 executable_path="geckodriver", options=None,
+                 service_log_path="geckodriver.log", firefox_options=None,
+                 service_args=None, desired_capabilities=None, log_path=None,
+                 keep_alive=True):
+        """Starts a new local session of Firefox.
+
+        Based on the combination and specificity of the various keyword
+        arguments, a capabilities dictionary will be constructed that
+        is passed to the remote end.
+
+        The keyword arguments given to this constructor are helpers to
+        more easily allow Firefox WebDriver sessions to be customised
+        with different options.  They are mapped on to a capabilities
+        dictionary that is passed on to the remote end.
+
+        As some of the options, such as `firefox_profile` and
+        `options.profile` are mutually exclusive, precedence is
+        given from how specific the setting is.  `capabilities` is the
+        least specific keyword argument, followed by `options`,
+        followed by `firefox_binary` and `firefox_profile`.
+
+        In practice this means that if `firefox_profile` and
+        `options.profile` are both set, the selected profile
+        instance will always come from the most specific variable.
+        In this case that would be `firefox_profile`.  This will result in
+        `options.profile` to be ignored because it is considered
+        a less specific setting than the top-level `firefox_profile`
+        keyword argument.  Similarily, if you had specified a
+        `capabilities["moz:firefoxOptions"]["profile"]` Base64 string,
+        this would rank below `options.profile`.
+
+        :param firefox_profile: Instance of ``FirefoxProfile`` object
+            or a string.  If undefined, a fresh profile will be created
+            in a temporary location on the system.
+        :param firefox_binary: Instance of ``FirefoxBinary`` or full
+            path to the Firefox binary.  If undefined, the system default
+            Firefox installation will  be used.
+        :param timeout: Time to wait for Firefox to launch when using
+            the extension connection.
+        :param capabilities: Dictionary of desired capabilities.
+        :param proxy: The proxy settings to us when communicating with
+            Firefox via the extension connection.
+        :param executable_path: Full path to override which geckodriver
+            binary to use for Firefox 47.0.1 and greater, which
+            defaults to picking up the binary from the system path.
+        :param options: Instance of ``options.Options``.
+        :param service_log_path: Where to log information from the driver.
+        :param firefox_options: Deprecated argument for options
+        :param service_args: List of args to pass to the driver service
+        :param desired_capabilities: alias of capabilities. In future
+            versions of this library, this will replace 'capabilities'.
+            This will make the signature consistent with RemoteWebDriver.
+        :param log_path: Deprecated argument for service_log_path
+        :param keep_alive: Whether to configure remote_connection.RemoteConnection to use
+             HTTP keep-alive.
+        """
+        if log_path:
+            warnings.warn('use service_log_path instead of log_path',
+                          DeprecationWarning, stacklevel=2)
+            service_log_path = log_path
+        if firefox_options:
+            warnings.warn('use options instead of firefox_options',
+                          DeprecationWarning, stacklevel=2)
+            options = firefox_options
+        self.binary = None
+        self.profile = None
+        self.service = None
+
+        # If desired capabilities is set, alias it to capabilities.
+        # If both are set ignore desired capabilities.
+        if capabilities is None and desired_capabilities:
+            capabilities = desired_capabilities
+
+        if capabilities is None:
+            capabilities = DesiredCapabilities.FIREFOX.copy()
+        if options is None:
+            options = Options()
+
+        capabilities = dict(capabilities)
+
+        if capabilities.get("binary"):
+            self.binary = capabilities["binary"]
+
+        # options overrides capabilities
+        if options is not None:
+            if options.binary is not None:
+                self.binary = options.binary
+            if options.profile is not None:
+                self.profile = options.profile
+
+        # firefox_binary and firefox_profile
+        # override options
+        if firefox_binary is not None:
+            if isinstance(firefox_binary, basestring):
+                firefox_binary = FirefoxBinary(firefox_binary)
+            self.binary = firefox_binary
+            options.binary = firefox_binary
+        if firefox_profile is not None:
+            if isinstance(firefox_profile, basestring):
+                firefox_profile = FirefoxProfile(firefox_profile)
+            self.profile = firefox_profile
+            options.profile = firefox_profile
+
+        # W3C remote
+        # TODO(ato): Perform conformance negotiation
+
+        if capabilities.get("marionette"):
+            capabilities.pop("marionette")
+            self.service = Service(
+                executable_path,
+                service_args=service_args,
+                log_path=service_log_path)
+            self.service.start()
+
+            capabilities.update(options.to_capabilities())
+
+            executor = FirefoxRemoteConnection(
+                remote_server_addr=self.service.service_url)
+            RemoteWebDriver.__init__(
+                self,
+                command_executor=executor,
+                desired_capabilities=capabilities,
+                keep_alive=True)
+
+        # Selenium remote
+        else:
+            if self.binary is None:
+                self.binary = FirefoxBinary()
+            if self.profile is None:
+                self.profile = FirefoxProfile()
+
+            # disable native events if globally disabled
+            self.profile.native_events_enabled = (
+                self.NATIVE_EVENTS_ALLOWED and self.profile.native_events_enabled)
+
+            if proxy is not None:
+                proxy.add_to_capabilities(capabilities)
+
+            executor = ExtensionConnection("127.0.0.1", self.profile,
+                                           self.binary, timeout)
+            RemoteWebDriver.__init__(
+                self,
+                command_executor=executor,
+                desired_capabilities=capabilities,
+                keep_alive=keep_alive)
+
+        self._is_remote = False
+
+    def quit(self):
+        """Quits the driver and close every associated window."""
+        try:
+            RemoteWebDriver.quit(self)
+        except Exception:
+            # We don't care about the message because something probably has gone wrong
+            pass
+
+        if self.w3c:
+            self.service.stop()
+        else:
+            self.binary.kill()
+
+        if self.profile is not None:
+            try:
+                shutil.rmtree(self.profile.path)
+                if self.profile.tempfolder is not None:
+                    shutil.rmtree(self.profile.tempfolder)
+            except Exception as e:
+                print(str(e))
+
+    @property
+    def firefox_profile(self):
+        return self.profile
+
+    # Extension commands:
+
+    def set_context(self, context):
+        self.execute("SET_CONTEXT", {"context": context})
+
+    @contextmanager
+    def context(self, context):
+        """Sets the context that Selenium commands are running in using
+        a `with` statement. The state of the context on the server is
+        saved before entering the block, and restored upon exiting it.
+
+        :param context: Context, may be one of the class properties
+            `CONTEXT_CHROME` or `CONTEXT_CONTENT`.
+
+        Usage example::
+
+            with selenium.context(selenium.CONTEXT_CHROME):
+                # chrome scope
+                ... do stuff ...
+        """
+        initial_context = self.execute('GET_CONTEXT').pop('value')
+        self.set_context(context)
+        try:
+            yield
+        finally:
+            self.set_context(initial_context)
+
+    def install_addon(self, path, temporary=None):
+        """
+        Installs Firefox addon.
+
+        Returns identifier of installed addon. This identifier can later
+        be used to uninstall addon.
+
+        :param path: Absolute path to the addon that will be installed.
+
+        :Usage:
+            driver.install_addon('/path/to/firebug.xpi')
+        """
+        payload = {"path": path}
+        if temporary is not None:
+            payload["temporary"] = temporary
+        return self.execute("INSTALL_ADDON", payload)["value"]
+
+    def uninstall_addon(self, identifier):
+        """
+        Uninstalls Firefox addon using its identifier.
+
+        :Usage:
+            driver.uninstall_addon('addon@foo.com')
+        """
+        self.execute("UNINSTALL_ADDON", {"id": identifier})

二进制
selenium-3.141.0/build/lib/selenium/webdriver/firefox/webdriver.xpi


+ 69 - 0
selenium-3.141.0/build/lib/selenium/webdriver/firefox/webdriver_prefs.json

@@ -0,0 +1,69 @@
+{
+  "frozen": {
+    "app.update.auto": false,
+    "app.update.enabled": false,
+    "browser.displayedE10SNotice": 4,
+    "browser.download.manager.showWhenStarting": false,
+    "browser.EULA.override": true,
+    "browser.EULA.3.accepted": true,
+    "browser.link.open_external": 2,
+    "browser.link.open_newwindow": 2,
+    "browser.offline": false,
+    "browser.reader.detectedFirstArticle": true,
+    "browser.safebrowsing.enabled": false,
+    "browser.safebrowsing.malware.enabled": false,
+    "browser.search.update": false,
+    "browser.selfsupport.url" : "",
+    "browser.sessionstore.resume_from_crash": false,
+    "browser.shell.checkDefaultBrowser": false,
+    "browser.tabs.warnOnClose": false,
+    "browser.tabs.warnOnOpen": false,
+    "datareporting.healthreport.service.enabled": false,
+    "datareporting.healthreport.uploadEnabled": false,
+    "datareporting.healthreport.service.firstRun": false,
+    "datareporting.healthreport.logging.consoleEnabled": false,
+    "datareporting.policy.dataSubmissionEnabled": false,
+    "datareporting.policy.dataSubmissionPolicyAccepted": false,
+    "devtools.errorconsole.enabled": true,
+    "dom.disable_open_during_load": false,
+    "extensions.autoDisableScopes": 10,
+    "extensions.blocklist.enabled": false,
+    "extensions.checkCompatibility.nightly": false,
+    "extensions.update.enabled": false,
+    "extensions.update.notifyUser": false,
+    "javascript.enabled": true,
+    "network.manage-offline-status": false,
+    "network.http.phishy-userpass-length": 255,
+    "offline-apps.allow_by_default": true,
+    "prompts.tab_modal.enabled": false,
+    "security.fileuri.origin_policy": 3,
+    "security.fileuri.strict_origin_policy": false,
+    "signon.rememberSignons": false,
+    "toolkit.networkmanager.disable": true,
+    "toolkit.telemetry.prompted": 2,
+    "toolkit.telemetry.enabled": false,
+    "toolkit.telemetry.rejected": true,
+    "xpinstall.signatures.required": false,
+    "xpinstall.whitelist.required": false
+  },
+  "mutable": {
+    "browser.dom.window.dump.enabled": true,
+    "browser.laterrun.enabled": false,
+    "browser.newtab.url": "about:blank",
+    "browser.newtabpage.enabled": false,
+    "browser.startup.page": 0,
+    "browser.startup.homepage": "about:blank",
+    "browser.startup.homepage_override.mstone": "ignore",
+    "browser.usedOnWindows10.introURL": "about:blank",
+    "dom.max_chrome_script_run_time": 30,
+    "dom.max_script_run_time": 30,
+    "dom.report_all_js_exceptions": true,
+    "javascript.options.showInConsole": true,
+    "network.captive-portal-service.enabled": false,
+    "security.csp.enable": false,
+    "startup.homepage_welcome_url": "about:blank",
+    "startup.homepage_welcome_url.additional": "about:blank",
+    "webdriver_accept_untrusted_certs": true,
+    "webdriver_assume_untrusted_issuer": true
+  }
+}

+ 49 - 0
selenium-3.141.0/build/lib/selenium/webdriver/firefox/webelement.py

@@ -0,0 +1,49 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.remote.webelement import WebElement as RemoteWebElement
+
+
+class FirefoxWebElement(RemoteWebElement):
+
+    @property
+    def anonymous_children(self):
+        """Retrieve the anonymous children of this element in an XBL
+        context.  This is only available in chrome context.
+
+        See the  `anonymous content documentation
+        <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XBL/XBL_1.0_Reference/Anonymous_Content>`_
+        on MDN for more information.
+
+        """
+        return self._execute(
+            "ELEMENT_GET_ANONYMOUS_CHILDREN",
+            {"value": None})
+
+    def find_anonymous_element_by_attribute(self, name, value):
+        """Retrieve an anonymous descendant with a specified attribute
+        value.  Typically used with an (arbitrary) anonid attribute to
+        retrieve a specific anonymous child in an XBL binding.
+
+        See the  `anonymous content documentation
+        <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XBL/XBL_1.0_Reference/Anonymous_Content>`_
+        on MDN for more information.
+
+        """
+        return self._execute(
+            "ELEMENT_FIND_ANONYMOUS_ELEMENTS_BY_ATTRIBUTE",
+            {"name": name, "value": value})["value"]

二进制
selenium-3.141.0/build/lib/selenium/webdriver/firefox/x86/x_ignore_nofocus.so


+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/ie/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 351 - 0
selenium-3.141.0/build/lib/selenium/webdriver/ie/options.py

@@ -0,0 +1,351 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+
+
+class ElementScrollBehavior(object):
+    TOP = 0
+    BOTTOM = 1
+
+
+class Options(object):
+
+    KEY = 'se:ieOptions'
+    SWITCHES = 'ie.browserCommandLineSwitches'
+
+    BROWSER_ATTACH_TIMEOUT = 'browserAttachTimeout'
+    ELEMENT_SCROLL_BEHAVIOR = 'elementScrollBehavior'
+    ENSURE_CLEAN_SESSION = 'ie.ensureCleanSession'
+    FILE_UPLOAD_DIALOG_TIMEOUT = 'ie.fileUploadDialogTimeout'
+    FORCE_CREATE_PROCESS_API = 'ie.forceCreateProcessApi'
+    FORCE_SHELL_WINDOWS_API = 'ie.forceShellWindowsApi'
+    FULL_PAGE_SCREENSHOT = 'ie.enableFullPageScreenshot'
+    IGNORE_PROTECTED_MODE_SETTINGS = 'ignoreProtectedModeSettings'
+    IGNORE_ZOOM_LEVEL = 'ignoreZoomSetting'
+    INITIAL_BROWSER_URL = 'initialBrowserUrl'
+    NATIVE_EVENTS = 'nativeEvents'
+    PERSISTENT_HOVER = 'enablePersistentHover'
+    REQUIRE_WINDOW_FOCUS = 'requireWindowFocus'
+    USE_PER_PROCESS_PROXY = 'ie.usePerProcessProxy'
+    VALIDATE_COOKIE_DOCUMENT_TYPE = 'ie.validateCookieDocumentType'
+
+    def __init__(self):
+        self._arguments = []
+        self._options = {}
+        self._additional = {}
+        self._caps = DesiredCapabilities.INTERNETEXPLORER.copy()
+
+    @property
+    def arguments(self):
+        """ Returns a list of browser process arguments """
+        return self._arguments
+
+    def add_argument(self, argument):
+        """ Add argument to be used for the browser process """
+        if argument is None:
+            raise ValueError()
+        self._arguments.append(argument)
+
+    @property
+    def options(self):
+        """ Returns a dictionary of browser options """
+        return self._options
+
+    @property
+    def capabilities(self):
+        return self._caps
+
+    def set_capability(self, name, value):
+        """Sets a capability."""
+        self._caps[name] = value
+
+    @property
+    def browser_attach_timeout(self):
+        """ Returns the options Browser Attach Timeout in milliseconds """
+        return self._options.get(self.BROWSER_ATTACH_TIMEOUT)
+
+    @browser_attach_timeout.setter
+    def browser_attach_timeout(self, value):
+        """
+        Sets the options Browser Attach Timeout
+
+        :Args:
+         - value: Timeout in milliseconds
+
+        """
+        if not isinstance(value, int):
+            raise ValueError('Browser Attach Timeout must be an integer.')
+        self._options[self.BROWSER_ATTACH_TIMEOUT] = value
+
+    @property
+    def element_scroll_behavior(self):
+        """ Returns the options Element Scroll Behavior in milliseconds """
+        return self._options.get(self.ELEMENT_SCROLL_BEHAVIOR)
+
+    @element_scroll_behavior.setter
+    def element_scroll_behavior(self, value):
+        """
+        Sets the options Element Scroll Behavior
+
+        :Args:
+         - value: 0 - Top, 1 - Bottom
+
+        """
+        if value not in [ElementScrollBehavior.TOP, ElementScrollBehavior.BOTTOM]:
+            raise ValueError('Element Scroll Behavior out of range.')
+        self._options[self.ELEMENT_SCROLL_BEHAVIOR] = value
+
+    @property
+    def ensure_clean_session(self):
+        """ Returns the options Ensure Clean Session value """
+        return self._options.get(self.ENSURE_CLEAN_SESSION)
+
+    @ensure_clean_session.setter
+    def ensure_clean_session(self, value):
+        """
+        Sets the options Ensure Clean Session value
+
+        :Args:
+         - value: boolean value
+
+        """
+        self._options[self.ENSURE_CLEAN_SESSION] = value
+
+    @property
+    def file_upload_dialog_timeout(self):
+        """ Returns the options File Upload Dialog Timeout in milliseconds """
+        return self._options.get(self.FILE_UPLOAD_DIALOG_TIMEOUT)
+
+    @file_upload_dialog_timeout.setter
+    def file_upload_dialog_timeout(self, value):
+        """
+        Sets the options File Upload Dialog Timeout value
+
+        :Args:
+         - value: Timeout in milliseconds
+
+        """
+        if not isinstance(value, int):
+            raise ValueError('File Upload Dialog Timeout must be an integer.')
+        self._options[self.FILE_UPLOAD_DIALOG_TIMEOUT] = value
+
+    @property
+    def force_create_process_api(self):
+        """ Returns the options Force Create Process Api value """
+        return self._options.get(self.FORCE_CREATE_PROCESS_API)
+
+    @force_create_process_api.setter
+    def force_create_process_api(self, value):
+        """
+        Sets the options Force Create Process Api value
+
+        :Args:
+         - value: boolean value
+
+        """
+        self._options[self.FORCE_CREATE_PROCESS_API] = value
+
+    @property
+    def force_shell_windows_api(self):
+        """ Returns the options Force Shell Windows Api value """
+        return self._options.get(self.FORCE_SHELL_WINDOWS_API)
+
+    @force_shell_windows_api.setter
+    def force_shell_windows_api(self, value):
+        """
+        Sets the options Force Shell Windows Api value
+
+        :Args:
+         - value: boolean value
+
+        """
+        self._options[self.FORCE_SHELL_WINDOWS_API] = value
+
+    @property
+    def full_page_screenshot(self):
+        """ Returns the options Full Page Screenshot value """
+        return self._options.get(self.FULL_PAGE_SCREENSHOT)
+
+    @full_page_screenshot.setter
+    def full_page_screenshot(self, value):
+        """
+        Sets the options Full Page Screenshot value
+
+        :Args:
+         - value: boolean value
+
+        """
+        self._options[self.FULL_PAGE_SCREENSHOT] = value
+
+    @property
+    def ignore_protected_mode_settings(self):
+        """ Returns the options Ignore Protected Mode Settings value """
+        return self._options.get(self.IGNORE_PROTECTED_MODE_SETTINGS)
+
+    @ignore_protected_mode_settings.setter
+    def ignore_protected_mode_settings(self, value):
+        """
+        Sets the options Ignore Protected Mode Settings value
+
+        :Args:
+         - value: boolean value
+
+        """
+        self._options[self.IGNORE_PROTECTED_MODE_SETTINGS] = value
+
+    @property
+    def ignore_zoom_level(self):
+        """ Returns the options Ignore Zoom Level value """
+        return self._options.get(self.IGNORE_ZOOM_LEVEL)
+
+    @ignore_zoom_level.setter
+    def ignore_zoom_level(self, value):
+        """
+        Sets the options Ignore Zoom Level value
+
+        :Args:
+         - value: boolean value
+
+        """
+        self._options[self.IGNORE_ZOOM_LEVEL] = value
+
+    @property
+    def initial_browser_url(self):
+        """ Returns the options Initial Browser Url value """
+        return self._options.get(self.INITIAL_BROWSER_URL)
+
+    @initial_browser_url.setter
+    def initial_browser_url(self, value):
+        """
+        Sets the options Initial Browser Url value
+
+        :Args:
+         - value: URL string
+
+        """
+        self._options[self.INITIAL_BROWSER_URL] = value
+
+    @property
+    def native_events(self):
+        """ Returns the options Native Events value """
+        return self._options.get(self.NATIVE_EVENTS)
+
+    @native_events.setter
+    def native_events(self, value):
+        """
+        Sets the options Native Events value
+
+        :Args:
+         - value: boolean value
+
+        """
+        self._options[self.NATIVE_EVENTS] = value
+
+    @property
+    def persistent_hover(self):
+        """ Returns the options Persistent Hover value """
+        return self._options.get(self.PERSISTENT_HOVER)
+
+    @persistent_hover.setter
+    def persistent_hover(self, value):
+        """
+        Sets the options Persistent Hover value
+
+        :Args:
+         - value: boolean value
+
+        """
+        self._options[self.PERSISTENT_HOVER] = value
+
+    @property
+    def require_window_focus(self):
+        """ Returns the options Require Window Focus value """
+        return self._options.get(self.REQUIRE_WINDOW_FOCUS)
+
+    @require_window_focus.setter
+    def require_window_focus(self, value):
+        """
+        Sets the options Require Window Focus value
+
+        :Args:
+         - value: boolean value
+
+        """
+        self._options[self.REQUIRE_WINDOW_FOCUS] = value
+
+    @property
+    def use_per_process_proxy(self):
+        """ Returns the options User Per Process Proxy value """
+        return self._options.get(self.USE_PER_PROCESS_PROXY)
+
+    @use_per_process_proxy.setter
+    def use_per_process_proxy(self, value):
+        """
+        Sets the options User Per Process Proxy value
+
+        :Args:
+         - value: boolean value
+
+        """
+        self._options[self.USE_PER_PROCESS_PROXY] = value
+
+    @property
+    def validate_cookie_document_type(self):
+        """ Returns the options Validate Cookie Document Type value """
+        return self._options.get(self.VALIDATE_COOKIE_DOCUMENT_TYPE)
+
+    @validate_cookie_document_type.setter
+    def validate_cookie_document_type(self, value):
+        """
+        Sets the options Validate Cookie Document Type value
+
+        :Args:
+         - value: boolean value
+
+        """
+        self._options[self.VALIDATE_COOKIE_DOCUMENT_TYPE] = value
+
+    @property
+    def additional_options(self):
+        """ Returns the additional options """
+        return self._additional
+
+    def add_additional_option(self, name, value):
+        """
+        Adds an additional option not yet added as a safe option for IE
+
+        :Args:
+         - name: name of the option to add
+         - value: value of the option to add
+
+        """
+        self._additional[name] = value
+
+    def to_capabilities(self):
+        """ Marshals the IE options to a the correct object """
+        caps = self._caps
+
+        opts = self._options.copy()
+        if len(self._arguments) > 0:
+            opts[self.SWITCHES] = ' '.join(self._arguments)
+
+        if len(self._additional) > 0:
+            opts.update(self._additional)
+
+        if len(opts) > 0:
+            caps[Options.KEY] = opts
+        return caps

+ 50 - 0
selenium-3.141.0/build/lib/selenium/webdriver/ie/service.py

@@ -0,0 +1,50 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.common import service
+
+
+class Service(service.Service):
+    """
+    Object that manages the starting and stopping of the IEDriver
+    """
+
+    def __init__(self, executable_path, port=0, host=None, log_level=None, log_file=None):
+        """
+        Creates a new instance of the Service
+
+        :Args:
+         - executable_path : Path to the IEDriver
+         - port : Port the service is running on
+         - host : IP address the service port is bound
+         - log_level : Level of logging of service, may be "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE".
+           Default is "FATAL".
+         - log_file : Target of logging of service, may be "stdout", "stderr" or file path.
+           Default is "stdout"."""
+        self.service_args = []
+        if host is not None:
+            self.service_args.append("--host=%s" % host)
+        if log_level is not None:
+            self.service_args.append("--log-level=%s" % log_level)
+        if log_file is not None:
+            self.service_args.append("--log-file=%s" % log_file)
+
+        service.Service.__init__(self, executable_path, port=port,
+                                 start_error_message="Please download from http://selenium-release.storage.googleapis.com/index.html and read up at https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver")
+
+    def command_line_args(self):
+        return ["--port=%d" % self.port] + self.service_args

+ 105 - 0
selenium-3.141.0/build/lib/selenium/webdriver/ie/webdriver.py

@@ -0,0 +1,105 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import warnings
+
+from selenium.webdriver.common import utils
+from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
+from .service import Service
+from .options import Options
+
+DEFAULT_TIMEOUT = 30
+DEFAULT_PORT = 0
+DEFAULT_HOST = None
+DEFAULT_LOG_LEVEL = None
+DEFAULT_SERVICE_LOG_PATH = None
+
+
+class WebDriver(RemoteWebDriver):
+    """ Controls the IEServerDriver and allows you to drive Internet Explorer """
+
+    def __init__(self, executable_path='IEDriverServer.exe', capabilities=None,
+                 port=DEFAULT_PORT, timeout=DEFAULT_TIMEOUT, host=DEFAULT_HOST,
+                 log_level=DEFAULT_LOG_LEVEL, service_log_path=DEFAULT_SERVICE_LOG_PATH, options=None,
+                 ie_options=None, desired_capabilities=None, log_file=None, keep_alive=False):
+        """
+        Creates a new instance of the chrome driver.
+
+        Starts the service and then creates new instance of chrome driver.
+
+        :Args:
+         - executable_path - path to the executable. If the default is used it assumes the executable is in the $PATH
+         - capabilities: capabilities Dictionary object
+         - port - port you would like the service to run, if left as 0, a free port will be found.
+         - timeout - no longer used, kept for backward compatibility
+         - host - IP address for the service
+         - log_level - log level you would like the service to run.
+         - service_log_path - target of logging of service, may be "stdout", "stderr" or file path.
+         - options - IE Options instance, providing additional IE options
+         - ie_options - Deprecated argument for options
+         - desired_capabilities - alias of capabilities; this will make the signature consistent with RemoteWebDriver.
+         - log_file - Deprecated argument for service_log_path
+         - keep_alive - Whether to configure RemoteConnection to use HTTP keep-alive.
+        """
+        if log_file:
+            warnings.warn('use service_log_path instead of log_file',
+                          DeprecationWarning, stacklevel=2)
+            service_log_path = log_file
+        if ie_options:
+            warnings.warn('use options instead of ie_options',
+                          DeprecationWarning, stacklevel=2)
+            options = ie_options
+        self.port = port
+        if self.port == 0:
+            self.port = utils.free_port()
+        self.host = host
+
+        # If both capabilities and desired capabilities are set, ignore desired capabilities.
+        if capabilities is None and desired_capabilities:
+            capabilities = desired_capabilities
+
+        if options is None:
+            if capabilities is None:
+                capabilities = self.create_options().to_capabilities()
+        else:
+            if capabilities is None:
+                capabilities = options.to_capabilities()
+            else:
+                # desired_capabilities stays as passed in
+                capabilities.update(options.to_capabilities())
+
+        self.iedriver = Service(
+            executable_path,
+            port=self.port,
+            host=self.host,
+            log_level=log_level,
+            log_file=service_log_path)
+
+        self.iedriver.start()
+
+        RemoteWebDriver.__init__(
+            self,
+            command_executor='http://localhost:%d' % self.port,
+            desired_capabilities=capabilities,
+            keep_alive=keep_alive)
+        self._is_remote = False
+
+    def quit(self):
+        RemoteWebDriver.quit(self)
+        self.iedriver.stop()
+
+    def create_options(self):
+        return Options()

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/opera/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 115 - 0
selenium-3.141.0/build/lib/selenium/webdriver/opera/options.py

@@ -0,0 +1,115 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.chrome.options import Options as ChromeOptions
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+
+
+class Options(ChromeOptions):
+    KEY = "operaOptions"
+
+    def __init__(self):
+        ChromeOptions.__init__(self)
+        self._android_package_name = ''
+        self._android_device_socket = ''
+        self._android_command_line_file = ''
+        self._caps = DesiredCapabilities.OPERA.copy()
+
+    @property
+    def capabilities(self):
+        return self._caps
+
+    def set_capability(self, name, value):
+        """Sets a capability."""
+        self._caps[name] = value
+
+    @property
+    def android_package_name(self):
+        """
+        Returns the name of the Opera package
+        """
+        return self._android_package_name
+
+    @android_package_name.setter
+    def android_package_name(self, value):
+        """
+        Allows you to set the package name
+
+        :Args:
+         - value: devtools socket name
+        """
+        self._android_package_name = value
+
+    @property
+    def android_device_socket(self):
+        """
+        Returns the name of the devtools socket
+        """
+        return self._android_device_socket
+
+    @android_device_socket.setter
+    def android_device_socket(self, value):
+        """
+        Allows you to set the devtools socket name
+
+        :Args:
+         - value: devtools socket name
+        """
+        self._android_device_socket = value
+
+    @property
+    def android_command_line_file(self):
+        """
+        Returns the path of the command line file
+        """
+        return self._android_command_line_file
+
+    @android_command_line_file.setter
+    def android_command_line_file(self, value):
+        """
+        Allows you to set where the command line file lives
+
+        :Args:
+         - value: command line file path
+        """
+        self._android_command_line_file = value
+
+    def to_capabilities(self):
+        """
+            Creates a capabilities with all the options that have been set and
+
+            returns a dictionary with everything
+        """
+        capabilities = ChromeOptions.to_capabilities(self)
+        capabilities.update(self._caps)
+        opera_options = capabilities[self.KEY]
+
+        if self.android_package_name:
+            opera_options["androidPackage"] = self.android_package_name
+        if self.android_device_socket:
+            opera_options["androidDeviceSocket"] = self.android_device_socket
+        if self.android_command_line_file:
+            opera_options["androidCommandLineFile"] = \
+                self.android_command_line_file
+        return capabilities
+
+
+class AndroidOptions(Options):
+
+    def __init__(self):
+        Options.__init__(self)
+        self.android_package_name = 'com.opera.browser'

+ 83 - 0
selenium-3.141.0/build/lib/selenium/webdriver/opera/webdriver.py

@@ -0,0 +1,83 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import warnings
+
+from selenium.webdriver.chrome.webdriver import WebDriver as ChromiumDriver
+from .options import Options
+
+
+class OperaDriver(ChromiumDriver):
+    """Controls the new OperaDriver and allows you
+    to drive the Opera browser based on Chromium."""
+
+    def __init__(self, executable_path=None, port=0,
+                 options=None, service_args=None,
+                 desired_capabilities=None, service_log_path=None,
+                 opera_options=None, keep_alive=True):
+        """
+        Creates a new instance of the operadriver.
+
+        Starts the service and then creates new instance of operadriver.
+
+        :Args:
+         - executable_path - path to the executable. If the default is used
+                             it assumes the executable is in the $PATH
+         - port - port you would like the service to run, if left as 0,
+                  a free port will be found.
+         - options: this takes an instance of OperaOptions
+         - service_args - List of args to pass to the driver service
+         - desired_capabilities: Dictionary object with non-browser specific
+         - service_log_path - Where to log information from the driver.
+         - opera_options - Deprecated argument for options
+           capabilities only, such as "proxy" or "loggingPref".
+        """
+        if opera_options:
+            warnings.warn('use options instead of opera_options',
+                          DeprecationWarning, stacklevel=2)
+            options = opera_options
+
+        executable_path = (executable_path if executable_path is not None
+                           else "operadriver")
+        ChromiumDriver.__init__(self,
+                                executable_path=executable_path,
+                                port=port,
+                                options=options,
+                                service_args=service_args,
+                                desired_capabilities=desired_capabilities,
+                                service_log_path=service_log_path,
+                                keep_alive=keep_alive)
+
+    def create_options(self):
+        return Options()
+
+
+class WebDriver(OperaDriver):
+    class ServiceType:
+        CHROMIUM = 2
+
+    def __init__(self,
+                 desired_capabilities=None,
+                 executable_path=None,
+                 port=0,
+                 service_log_path=None,
+                 service_args=None,
+                 options=None):
+        OperaDriver.__init__(self, executable_path=executable_path,
+                             port=port, options=options,
+                             service_args=service_args,
+                             desired_capabilities=desired_capabilities,
+                             service_log_path=service_log_path)

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/phantomjs/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 68 - 0
selenium-3.141.0/build/lib/selenium/webdriver/phantomjs/service.py

@@ -0,0 +1,68 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import os
+import tempfile
+from selenium.webdriver.common import service
+
+
+class Service(service.Service):
+    """
+    Object that manages the starting and stopping of PhantomJS / Ghostdriver
+    """
+
+    def __init__(self, executable_path, port=0, service_args=None, log_path=None):
+        """
+        Creates a new instance of the Service
+
+        :Args:
+         - executable_path : Path to PhantomJS binary
+         - port : Port the service is running on
+         - service_args : A List of other command line options to pass to PhantomJS
+         - log_path: Path for PhantomJS service to log to
+        """
+        self.service_args = service_args
+        if self.service_args is None:
+            self.service_args = []
+        else:
+            self.service_args = service_args[:]
+        if not log_path:
+            log_path = "ghostdriver.log"
+        if not self._args_contain("--cookies-file="):
+            self._cookie_temp_file_handle, self._cookie_temp_file = tempfile.mkstemp()
+            self.service_args.append("--cookies-file=" + self._cookie_temp_file)
+        else:
+            self._cookie_temp_file = None
+
+        service.Service.__init__(self, executable_path, port=port, log_file=open(log_path, 'w'))
+
+    def _args_contain(self, arg):
+        return len(list(filter(lambda x: x.startswith(arg), self.service_args))) > 0
+
+    def command_line_args(self):
+        return self.service_args + ["--webdriver=%d" % self.port]
+
+    @property
+    def service_url(self):
+        """
+        Gets the url of the GhostDriver Service
+        """
+        return "http://localhost:%d/wd/hub" % self.port
+
+    def send_remote_shutdown_command(self):
+        if self._cookie_temp_file:
+            os.close(self._cookie_temp_file_handle)
+            os.remove(self._cookie_temp_file)

+ 80 - 0
selenium-3.141.0/build/lib/selenium/webdriver/phantomjs/webdriver.py

@@ -0,0 +1,80 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import warnings
+
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
+from .service import Service
+
+
+class WebDriver(RemoteWebDriver):
+    """
+    Wrapper to communicate with PhantomJS through Ghostdriver.
+
+    You will need to follow all the directions here:
+    https://github.com/detro/ghostdriver
+    """
+
+    def __init__(self, executable_path="phantomjs",
+                 port=0, desired_capabilities=DesiredCapabilities.PHANTOMJS,
+                 service_args=None, service_log_path=None):
+        """
+        Creates a new instance of the PhantomJS / Ghostdriver.
+
+        Starts the service and then creates new instance of the driver.
+
+        :Args:
+         - executable_path - path to the executable. If the default is used it assumes the executable is in the $PATH
+         - port - port you would like the service to run, if left as 0, a free port will be found.
+         - desired_capabilities: Dictionary object with non-browser specific
+           capabilities only, such as "proxy" or "loggingPref".
+         - service_args : A List of command line arguments to pass to PhantomJS
+         - service_log_path: Path for phantomjs service to log to.
+        """
+        warnings.warn('Selenium support for PhantomJS has been deprecated, please use headless '
+                      'versions of Chrome or Firefox instead')
+        self.service = Service(
+            executable_path,
+            port=port,
+            service_args=service_args,
+            log_path=service_log_path)
+        self.service.start()
+
+        try:
+            RemoteWebDriver.__init__(
+                self,
+                command_executor=self.service.service_url,
+                desired_capabilities=desired_capabilities)
+        except Exception:
+            self.quit()
+            raise
+
+        self._is_remote = False
+
+    def quit(self):
+        """
+        Closes the browser and shuts down the PhantomJS executable
+        that is started when starting the PhantomJS
+        """
+        try:
+            RemoteWebDriver.quit(self)
+        except Exception:
+            # We don't care about the message because something probably has gone wrong
+            pass
+        finally:
+            self.service.stop()

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/remote/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 173 - 0
selenium-3.141.0/build/lib/selenium/webdriver/remote/command.py

@@ -0,0 +1,173 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+class Command(object):
+    """
+    Defines constants for the standard WebDriver commands.
+
+    While these constants have no meaning in and of themselves, they are
+    used to marshal commands through a service that implements WebDriver's
+    remote wire protocol:
+
+        https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol
+
+    """
+
+    # Keep in sync with org.openqa.selenium.remote.DriverCommand
+
+    STATUS = "status"
+    NEW_SESSION = "newSession"
+    GET_ALL_SESSIONS = "getAllSessions"
+    DELETE_SESSION = "deleteSession"
+    CLOSE = "close"
+    QUIT = "quit"
+    GET = "get"
+    GO_BACK = "goBack"
+    GO_FORWARD = "goForward"
+    REFRESH = "refresh"
+    ADD_COOKIE = "addCookie"
+    GET_COOKIE = "getCookie"
+    GET_ALL_COOKIES = "getCookies"
+    DELETE_COOKIE = "deleteCookie"
+    DELETE_ALL_COOKIES = "deleteAllCookies"
+    FIND_ELEMENT = "findElement"
+    FIND_ELEMENTS = "findElements"
+    FIND_CHILD_ELEMENT = "findChildElement"
+    FIND_CHILD_ELEMENTS = "findChildElements"
+    CLEAR_ELEMENT = "clearElement"
+    CLICK_ELEMENT = "clickElement"
+    SEND_KEYS_TO_ELEMENT = "sendKeysToElement"
+    SEND_KEYS_TO_ACTIVE_ELEMENT = "sendKeysToActiveElement"
+    SUBMIT_ELEMENT = "submitElement"
+    UPLOAD_FILE = "uploadFile"
+    GET_CURRENT_WINDOW_HANDLE = "getCurrentWindowHandle"
+    W3C_GET_CURRENT_WINDOW_HANDLE = "w3cGetCurrentWindowHandle"
+    GET_WINDOW_HANDLES = "getWindowHandles"
+    W3C_GET_WINDOW_HANDLES = "w3cGetWindowHandles"
+    GET_WINDOW_SIZE = "getWindowSize"
+    W3C_GET_WINDOW_SIZE = "w3cGetWindowSize"
+    W3C_GET_WINDOW_POSITION = "w3cGetWindowPosition"
+    GET_WINDOW_POSITION = "getWindowPosition"
+    SET_WINDOW_SIZE = "setWindowSize"
+    W3C_SET_WINDOW_SIZE = "w3cSetWindowSize"
+    SET_WINDOW_RECT = "setWindowRect"
+    GET_WINDOW_RECT = "getWindowRect"
+    SET_WINDOW_POSITION = "setWindowPosition"
+    W3C_SET_WINDOW_POSITION = "w3cSetWindowPosition"
+    SWITCH_TO_WINDOW = "switchToWindow"
+    SWITCH_TO_FRAME = "switchToFrame"
+    SWITCH_TO_PARENT_FRAME = "switchToParentFrame"
+    GET_ACTIVE_ELEMENT = "getActiveElement"
+    W3C_GET_ACTIVE_ELEMENT = "w3cGetActiveElement"
+    GET_CURRENT_URL = "getCurrentUrl"
+    GET_PAGE_SOURCE = "getPageSource"
+    GET_TITLE = "getTitle"
+    EXECUTE_SCRIPT = "executeScript"
+    W3C_EXECUTE_SCRIPT = "w3cExecuteScript"
+    W3C_EXECUTE_SCRIPT_ASYNC = "w3cExecuteScriptAsync"
+    GET_ELEMENT_TEXT = "getElementText"
+    GET_ELEMENT_VALUE = "getElementValue"
+    GET_ELEMENT_TAG_NAME = "getElementTagName"
+    SET_ELEMENT_SELECTED = "setElementSelected"
+    IS_ELEMENT_SELECTED = "isElementSelected"
+    IS_ELEMENT_ENABLED = "isElementEnabled"
+    IS_ELEMENT_DISPLAYED = "isElementDisplayed"
+    GET_ELEMENT_LOCATION = "getElementLocation"
+    GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW = "getElementLocationOnceScrolledIntoView"
+    GET_ELEMENT_SIZE = "getElementSize"
+    GET_ELEMENT_RECT = "getElementRect"
+    GET_ELEMENT_ATTRIBUTE = "getElementAttribute"
+    GET_ELEMENT_PROPERTY = "getElementProperty"
+    GET_ELEMENT_VALUE_OF_CSS_PROPERTY = "getElementValueOfCssProperty"
+    SCREENSHOT = "screenshot"
+    ELEMENT_SCREENSHOT = "elementScreenshot"
+    IMPLICIT_WAIT = "implicitlyWait"
+    EXECUTE_ASYNC_SCRIPT = "executeAsyncScript"
+    SET_SCRIPT_TIMEOUT = "setScriptTimeout"
+    SET_TIMEOUTS = "setTimeouts"
+    MAXIMIZE_WINDOW = "windowMaximize"
+    W3C_MAXIMIZE_WINDOW = "w3cMaximizeWindow"
+    GET_LOG = "getLog"
+    GET_AVAILABLE_LOG_TYPES = "getAvailableLogTypes"
+    FULLSCREEN_WINDOW = "fullscreenWindow"
+    MINIMIZE_WINDOW = "minimizeWindow"
+
+    # Alerts
+    DISMISS_ALERT = "dismissAlert"
+    W3C_DISMISS_ALERT = "w3cDismissAlert"
+    ACCEPT_ALERT = "acceptAlert"
+    W3C_ACCEPT_ALERT = "w3cAcceptAlert"
+    SET_ALERT_VALUE = "setAlertValue"
+    W3C_SET_ALERT_VALUE = "w3cSetAlertValue"
+    GET_ALERT_TEXT = "getAlertText"
+    W3C_GET_ALERT_TEXT = "w3cGetAlertText"
+    SET_ALERT_CREDENTIALS = "setAlertCredentials"
+
+    # Advanced user interactions
+    W3C_ACTIONS = "actions"
+    W3C_CLEAR_ACTIONS = "clearActionState"
+    CLICK = "mouseClick"
+    DOUBLE_CLICK = "mouseDoubleClick"
+    MOUSE_DOWN = "mouseButtonDown"
+    MOUSE_UP = "mouseButtonUp"
+    MOVE_TO = "mouseMoveTo"
+
+    # Screen Orientation
+    SET_SCREEN_ORIENTATION = "setScreenOrientation"
+    GET_SCREEN_ORIENTATION = "getScreenOrientation"
+
+    # Touch Actions
+    SINGLE_TAP = "touchSingleTap"
+    TOUCH_DOWN = "touchDown"
+    TOUCH_UP = "touchUp"
+    TOUCH_MOVE = "touchMove"
+    TOUCH_SCROLL = "touchScroll"
+    DOUBLE_TAP = "touchDoubleTap"
+    LONG_PRESS = "touchLongPress"
+    FLICK = "touchFlick"
+
+    # HTML 5
+    EXECUTE_SQL = "executeSql"
+
+    GET_LOCATION = "getLocation"
+    SET_LOCATION = "setLocation"
+
+    GET_APP_CACHE = "getAppCache"
+    GET_APP_CACHE_STATUS = "getAppCacheStatus"
+    CLEAR_APP_CACHE = "clearAppCache"
+
+    GET_LOCAL_STORAGE_ITEM = "getLocalStorageItem"
+    REMOVE_LOCAL_STORAGE_ITEM = "removeLocalStorageItem"
+    GET_LOCAL_STORAGE_KEYS = "getLocalStorageKeys"
+    SET_LOCAL_STORAGE_ITEM = "setLocalStorageItem"
+    CLEAR_LOCAL_STORAGE = "clearLocalStorage"
+    GET_LOCAL_STORAGE_SIZE = "getLocalStorageSize"
+
+    GET_SESSION_STORAGE_ITEM = "getSessionStorageItem"
+    REMOVE_SESSION_STORAGE_ITEM = "removeSessionStorageItem"
+    GET_SESSION_STORAGE_KEYS = "getSessionStorageKeys"
+    SET_SESSION_STORAGE_ITEM = "setSessionStorageItem"
+    CLEAR_SESSION_STORAGE = "clearSessionStorage"
+    GET_SESSION_STORAGE_SIZE = "getSessionStorageSize"
+
+    # Mobile
+    GET_NETWORK_CONNECTION = "getNetworkConnection"
+    SET_NETWORK_CONNECTION = "setNetworkConnection"
+    CURRENT_CONTEXT_HANDLE = "getCurrentContextHandle"
+    CONTEXT_HANDLES = "getContextHandles"
+    SWITCH_TO_CONTEXT = "switchToContext"

+ 245 - 0
selenium-3.141.0/build/lib/selenium/webdriver/remote/errorhandler.py

@@ -0,0 +1,245 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.common.exceptions import (ElementClickInterceptedException,
+                                        ElementNotInteractableException,
+                                        ElementNotSelectableException,
+                                        ElementNotVisibleException,
+                                        ErrorInResponseException,
+                                        InsecureCertificateException,
+                                        InvalidCoordinatesException,
+                                        InvalidElementStateException,
+                                        InvalidSessionIdException,
+                                        InvalidSelectorException,
+                                        ImeNotAvailableException,
+                                        ImeActivationFailedException,
+                                        InvalidArgumentException,
+                                        InvalidCookieDomainException,
+                                        JavascriptException,
+                                        MoveTargetOutOfBoundsException,
+                                        NoSuchCookieException,
+                                        NoSuchElementException,
+                                        NoSuchFrameException,
+                                        NoSuchWindowException,
+                                        NoAlertPresentException,
+                                        ScreenshotException,
+                                        SessionNotCreatedException,
+                                        StaleElementReferenceException,
+                                        TimeoutException,
+                                        UnableToSetCookieException,
+                                        UnexpectedAlertPresentException,
+                                        UnknownMethodException,
+                                        WebDriverException)
+
+try:
+    basestring
+except NameError:  # Python 3.x
+    basestring = str
+
+
+class ErrorCode(object):
+    """
+    Error codes defined in the WebDriver wire protocol.
+    """
+    # Keep in sync with org.openqa.selenium.remote.ErrorCodes and errorcodes.h
+    SUCCESS = 0
+    NO_SUCH_ELEMENT = [7, 'no such element']
+    NO_SUCH_FRAME = [8, 'no such frame']
+    UNKNOWN_COMMAND = [9, 'unknown command']
+    STALE_ELEMENT_REFERENCE = [10, 'stale element reference']
+    ELEMENT_NOT_VISIBLE = [11, 'element not visible']
+    INVALID_ELEMENT_STATE = [12, 'invalid element state']
+    UNKNOWN_ERROR = [13, 'unknown error']
+    ELEMENT_IS_NOT_SELECTABLE = [15, 'element not selectable']
+    JAVASCRIPT_ERROR = [17, 'javascript error']
+    XPATH_LOOKUP_ERROR = [19, 'invalid selector']
+    TIMEOUT = [21, 'timeout']
+    NO_SUCH_WINDOW = [23, 'no such window']
+    INVALID_COOKIE_DOMAIN = [24, 'invalid cookie domain']
+    UNABLE_TO_SET_COOKIE = [25, 'unable to set cookie']
+    UNEXPECTED_ALERT_OPEN = [26, 'unexpected alert open']
+    NO_ALERT_OPEN = [27, 'no such alert']
+    SCRIPT_TIMEOUT = [28, 'script timeout']
+    INVALID_ELEMENT_COORDINATES = [29, 'invalid element coordinates']
+    IME_NOT_AVAILABLE = [30, 'ime not available']
+    IME_ENGINE_ACTIVATION_FAILED = [31, 'ime engine activation failed']
+    INVALID_SELECTOR = [32, 'invalid selector']
+    SESSION_NOT_CREATED = [33, 'session not created']
+    MOVE_TARGET_OUT_OF_BOUNDS = [34, 'move target out of bounds']
+    INVALID_XPATH_SELECTOR = [51, 'invalid selector']
+    INVALID_XPATH_SELECTOR_RETURN_TYPER = [52, 'invalid selector']
+
+    ELEMENT_NOT_INTERACTABLE = [60, 'element not interactable']
+    INSECURE_CERTIFICATE = ['insecure certificate']
+    INVALID_ARGUMENT = [61, 'invalid argument']
+    INVALID_COORDINATES = ['invalid coordinates']
+    INVALID_SESSION_ID = ['invalid session id']
+    NO_SUCH_COOKIE = [62, 'no such cookie']
+    UNABLE_TO_CAPTURE_SCREEN = [63, 'unable to capture screen']
+    ELEMENT_CLICK_INTERCEPTED = [64, 'element click intercepted']
+    UNKNOWN_METHOD = ['unknown method exception']
+
+    METHOD_NOT_ALLOWED = [405, 'unsupported operation']
+
+
+class ErrorHandler(object):
+    """
+    Handles errors returned by the WebDriver server.
+    """
+    def check_response(self, response):
+        """
+        Checks that a JSON response from the WebDriver does not have an error.
+
+        :Args:
+         - response - The JSON response from the WebDriver server as a dictionary
+           object.
+
+        :Raises: If the response contains an error message.
+        """
+        status = response.get('status', None)
+        if status is None or status == ErrorCode.SUCCESS:
+            return
+        value = None
+        message = response.get("message", "")
+        screen = response.get("screen", "")
+        stacktrace = None
+        if isinstance(status, int):
+            value_json = response.get('value', None)
+            if value_json and isinstance(value_json, basestring):
+                import json
+                try:
+                    value = json.loads(value_json)
+                    if len(value.keys()) == 1:
+                        value = value['value']
+                    status = value.get('error', None)
+                    if status is None:
+                        status = value["status"]
+                        message = value["value"]
+                        if not isinstance(message, basestring):
+                            value = message
+                            message = message.get('message')
+                    else:
+                        message = value.get('message', None)
+                except ValueError:
+                    pass
+
+        exception_class = ErrorInResponseException
+        if status in ErrorCode.NO_SUCH_ELEMENT:
+            exception_class = NoSuchElementException
+        elif status in ErrorCode.NO_SUCH_FRAME:
+            exception_class = NoSuchFrameException
+        elif status in ErrorCode.NO_SUCH_WINDOW:
+            exception_class = NoSuchWindowException
+        elif status in ErrorCode.STALE_ELEMENT_REFERENCE:
+            exception_class = StaleElementReferenceException
+        elif status in ErrorCode.ELEMENT_NOT_VISIBLE:
+            exception_class = ElementNotVisibleException
+        elif status in ErrorCode.INVALID_ELEMENT_STATE:
+            exception_class = InvalidElementStateException
+        elif status in ErrorCode.INVALID_SELECTOR \
+                or status in ErrorCode.INVALID_XPATH_SELECTOR \
+                or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:
+            exception_class = InvalidSelectorException
+        elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:
+            exception_class = ElementNotSelectableException
+        elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:
+            exception_class = ElementNotInteractableException
+        elif status in ErrorCode.INVALID_COOKIE_DOMAIN:
+            exception_class = InvalidCookieDomainException
+        elif status in ErrorCode.UNABLE_TO_SET_COOKIE:
+            exception_class = UnableToSetCookieException
+        elif status in ErrorCode.TIMEOUT:
+            exception_class = TimeoutException
+        elif status in ErrorCode.SCRIPT_TIMEOUT:
+            exception_class = TimeoutException
+        elif status in ErrorCode.UNKNOWN_ERROR:
+            exception_class = WebDriverException
+        elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:
+            exception_class = UnexpectedAlertPresentException
+        elif status in ErrorCode.NO_ALERT_OPEN:
+            exception_class = NoAlertPresentException
+        elif status in ErrorCode.IME_NOT_AVAILABLE:
+            exception_class = ImeNotAvailableException
+        elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:
+            exception_class = ImeActivationFailedException
+        elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:
+            exception_class = MoveTargetOutOfBoundsException
+        elif status in ErrorCode.JAVASCRIPT_ERROR:
+            exception_class = JavascriptException
+        elif status in ErrorCode.SESSION_NOT_CREATED:
+            exception_class = SessionNotCreatedException
+        elif status in ErrorCode.INVALID_ARGUMENT:
+            exception_class = InvalidArgumentException
+        elif status in ErrorCode.NO_SUCH_COOKIE:
+            exception_class = NoSuchCookieException
+        elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:
+            exception_class = ScreenshotException
+        elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:
+            exception_class = ElementClickInterceptedException
+        elif status in ErrorCode.INSECURE_CERTIFICATE:
+            exception_class = InsecureCertificateException
+        elif status in ErrorCode.INVALID_COORDINATES:
+            exception_class = InvalidCoordinatesException
+        elif status in ErrorCode.INVALID_SESSION_ID:
+            exception_class = InvalidSessionIdException
+        elif status in ErrorCode.UNKNOWN_METHOD:
+            exception_class = UnknownMethodException
+        else:
+            exception_class = WebDriverException
+        if value == '' or value is None:
+            value = response['value']
+        if isinstance(value, basestring):
+            if exception_class == ErrorInResponseException:
+                raise exception_class(response, value)
+            raise exception_class(value)
+        if message == "" and 'message' in value:
+            message = value['message']
+
+        screen = None
+        if 'screen' in value:
+            screen = value['screen']
+
+        stacktrace = None
+        if 'stackTrace' in value and value['stackTrace']:
+            stacktrace = []
+            try:
+                for frame in value['stackTrace']:
+                    line = self._value_or_default(frame, 'lineNumber', '')
+                    file = self._value_or_default(frame, 'fileName', '<anonymous>')
+                    if line:
+                        file = "%s:%s" % (file, line)
+                    meth = self._value_or_default(frame, 'methodName', '<anonymous>')
+                    if 'className' in frame:
+                        meth = "%s.%s" % (frame['className'], meth)
+                    msg = "    at %s (%s)"
+                    msg = msg % (meth, file)
+                    stacktrace.append(msg)
+            except TypeError:
+                pass
+        if exception_class == ErrorInResponseException:
+            raise exception_class(response, message)
+        elif exception_class == UnexpectedAlertPresentException:
+            alert_text = None
+            if 'data' in value:
+                alert_text = value['data'].get('text')
+            elif 'alert' in value:
+                alert_text = value['alert'].get('text')
+            raise exception_class(message, screen, stacktrace, alert_text)
+        raise exception_class(message, screen, stacktrace)
+
+    def _value_or_default(self, obj, key, default):
+        return obj[key] if key in obj else default

+ 58 - 0
selenium-3.141.0/build/lib/selenium/webdriver/remote/file_detector.py

@@ -0,0 +1,58 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import abc
+import os
+from selenium.webdriver.common.utils import keys_to_typing
+
+
+class FileDetector(object):
+    """
+    Used for identifying whether a sequence of chars represents the path to a
+    file.
+    """
+    __metaclass__ = abc.ABCMeta
+
+    @abc.abstractmethod
+    def is_local_file(self, *keys):
+        return
+
+
+class UselessFileDetector(FileDetector):
+    """
+    A file detector that never finds anything.
+    """
+    def is_local_file(self, *keys):
+        return None
+
+
+class LocalFileDetector(FileDetector):
+    """
+    Detects files on the local disk.
+    """
+    def is_local_file(self, *keys):
+        file_path = ''.join(keys_to_typing(keys))
+
+        if not file_path:
+            return None
+
+        try:
+            if os.path.isfile(file_path):
+                return file_path
+        except Exception:
+            pass
+        return None

文件差异内容过多而无法显示
+ 8 - 0
selenium-3.141.0/build/lib/selenium/webdriver/remote/getAttribute.js


文件差异内容过多而无法显示
+ 101 - 0
selenium-3.141.0/build/lib/selenium/webdriver/remote/isDisplayed.js


+ 85 - 0
selenium-3.141.0/build/lib/selenium/webdriver/remote/mobile.py

@@ -0,0 +1,85 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from .command import Command
+
+
+class Mobile(object):
+
+    class ConnectionType(object):
+
+        def __init__(self, mask):
+            self.mask = mask
+
+        @property
+        def airplane_mode(self):
+            return self.mask % 2 == 1
+
+        @property
+        def wifi(self):
+            return (self.mask / 2) % 2 == 1
+
+        @property
+        def data(self):
+            return (self.mask / 4) > 0
+
+    ALL_NETWORK = ConnectionType(6)
+    WIFI_NETWORK = ConnectionType(2)
+    DATA_NETWORK = ConnectionType(4)
+    AIRPLANE_MODE = ConnectionType(1)
+
+    def __init__(self, driver):
+        self._driver = driver
+
+    @property
+    def network_connection(self):
+        return self.ConnectionType(self._driver.execute(Command.GET_NETWORK_CONNECTION)['value'])
+
+    def set_network_connection(self, network):
+        """
+        Set the network connection for the remote device.
+
+        Example of setting airplane mode::
+
+            driver.mobile.set_network_connection(driver.mobile.AIRPLANE_MODE)
+        """
+        mode = network.mask if isinstance(network, self.ConnectionType) else network
+        return self.ConnectionType(self._driver.execute(
+            Command.SET_NETWORK_CONNECTION, {
+                'name': 'network_connection',
+                'parameters': {'type': mode}})['value'])
+
+    @property
+    def context(self):
+        """
+        returns the current context (Native or WebView).
+        """
+        return self._driver.execute(Command.CURRENT_CONTEXT_HANDLE)
+
+    @property
+    def contexts(self):
+        """
+        returns a list of available contexts
+        """
+        return self._driver.execute(Command.CONTEXT_HANDLES)
+
+    @context.setter
+    def context(self, new_context):
+        """
+        sets the current context
+        """
+        self._driver.execute(Command.SWITCH_TO_CONTEXT, {"name": new_context})

+ 441 - 0
selenium-3.141.0/build/lib/selenium/webdriver/remote/remote_connection.py

@@ -0,0 +1,441 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import base64
+import logging
+import platform
+import socket
+import string
+
+import urllib3
+
+try:
+    from urllib import parse
+except ImportError:  # above is available in py3+, below is py2.7
+    import urlparse as parse
+
+from selenium.webdriver.common import utils as common_utils
+from selenium import __version__
+from .command import Command
+from .errorhandler import ErrorCode
+from . import utils
+
+LOGGER = logging.getLogger(__name__)
+
+
+class RemoteConnection(object):
+    """A connection with the Remote WebDriver server.
+
+    Communicates with the server using the WebDriver wire protocol:
+    https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol"""
+
+    _timeout = socket._GLOBAL_DEFAULT_TIMEOUT
+
+    @classmethod
+    def get_timeout(cls):
+        """
+        :Returns:
+            Timeout value in seconds for all http requests made to the Remote Connection
+        """
+        return None if cls._timeout == socket._GLOBAL_DEFAULT_TIMEOUT else cls._timeout
+
+    @classmethod
+    def set_timeout(cls, timeout):
+        """
+        Override the default timeout
+
+        :Args:
+            - timeout - timeout value for http requests in seconds
+        """
+        cls._timeout = timeout
+
+    @classmethod
+    def reset_timeout(cls):
+        """
+        Reset the http request timeout to socket._GLOBAL_DEFAULT_TIMEOUT
+        """
+        cls._timeout = socket._GLOBAL_DEFAULT_TIMEOUT
+
+    @classmethod
+    def get_remote_connection_headers(cls, parsed_url, keep_alive=False):
+        """
+        Get headers for remote request.
+
+        :Args:
+         - parsed_url - The parsed url
+         - keep_alive (Boolean) - Is this a keep-alive connection (default: False)
+        """
+
+        system = platform.system().lower()
+        if system == "darwin":
+            system = "mac"
+
+        headers = {
+            'Accept': 'application/json',
+            'Content-Type': 'application/json;charset=UTF-8',
+            'User-Agent': 'selenium/{} (python {})'.format(__version__, system)
+        }
+
+        if parsed_url.username:
+            base64string = base64.b64encode('{0.username}:{0.password}'.format(parsed_url).encode())
+            headers.update({
+                'Authorization': 'Basic {}'.format(base64string.decode())
+            })
+
+        if keep_alive:
+            headers.update({
+                'Connection': 'keep-alive'
+            })
+
+        return headers
+
+    def __init__(self, remote_server_addr, keep_alive=False, resolve_ip=True):
+        # Attempt to resolve the hostname and get an IP address.
+        self.keep_alive = keep_alive
+        parsed_url = parse.urlparse(remote_server_addr)
+        if parsed_url.hostname and resolve_ip:
+            port = parsed_url.port or None
+            if parsed_url.scheme == "https":
+                ip = parsed_url.hostname
+            elif port and not common_utils.is_connectable(port, parsed_url.hostname):
+                ip = None
+                LOGGER.info('Could not connect to port {} on host '
+                            '{}'.format(port, parsed_url.hostname))
+            else:
+                ip = common_utils.find_connectable_ip(parsed_url.hostname,
+                                                      port=port)
+            if ip:
+                netloc = ip
+                if parsed_url.port:
+                    netloc = common_utils.join_host_port(netloc,
+                                                         parsed_url.port)
+                if parsed_url.username:
+                    auth = parsed_url.username
+                    if parsed_url.password:
+                        auth += ':%s' % parsed_url.password
+                    netloc = '%s@%s' % (auth, netloc)
+                remote_server_addr = parse.urlunparse(
+                    (parsed_url.scheme, netloc, parsed_url.path,
+                     parsed_url.params, parsed_url.query, parsed_url.fragment))
+            else:
+                LOGGER.info('Could not get IP address for host: %s' %
+                            parsed_url.hostname)
+
+        self._url = remote_server_addr
+        if keep_alive:
+            self._conn = urllib3.PoolManager(timeout=self._timeout)
+
+        self._commands = {
+            Command.STATUS: ('GET', '/status'),
+            Command.NEW_SESSION: ('POST', '/session'),
+            Command.GET_ALL_SESSIONS: ('GET', '/sessions'),
+            Command.QUIT: ('DELETE', '/session/$sessionId'),
+            Command.GET_CURRENT_WINDOW_HANDLE:
+                ('GET', '/session/$sessionId/window_handle'),
+            Command.W3C_GET_CURRENT_WINDOW_HANDLE:
+                ('GET', '/session/$sessionId/window'),
+            Command.GET_WINDOW_HANDLES:
+                ('GET', '/session/$sessionId/window_handles'),
+            Command.W3C_GET_WINDOW_HANDLES:
+                ('GET', '/session/$sessionId/window/handles'),
+            Command.GET: ('POST', '/session/$sessionId/url'),
+            Command.GO_FORWARD: ('POST', '/session/$sessionId/forward'),
+            Command.GO_BACK: ('POST', '/session/$sessionId/back'),
+            Command.REFRESH: ('POST', '/session/$sessionId/refresh'),
+            Command.EXECUTE_SCRIPT: ('POST', '/session/$sessionId/execute'),
+            Command.W3C_EXECUTE_SCRIPT:
+                ('POST', '/session/$sessionId/execute/sync'),
+            Command.W3C_EXECUTE_SCRIPT_ASYNC:
+                ('POST', '/session/$sessionId/execute/async'),
+            Command.GET_CURRENT_URL: ('GET', '/session/$sessionId/url'),
+            Command.GET_TITLE: ('GET', '/session/$sessionId/title'),
+            Command.GET_PAGE_SOURCE: ('GET', '/session/$sessionId/source'),
+            Command.SCREENSHOT: ('GET', '/session/$sessionId/screenshot'),
+            Command.ELEMENT_SCREENSHOT: ('GET', '/session/$sessionId/element/$id/screenshot'),
+            Command.FIND_ELEMENT: ('POST', '/session/$sessionId/element'),
+            Command.FIND_ELEMENTS: ('POST', '/session/$sessionId/elements'),
+            Command.W3C_GET_ACTIVE_ELEMENT: ('GET', '/session/$sessionId/element/active'),
+            Command.GET_ACTIVE_ELEMENT:
+                ('POST', '/session/$sessionId/element/active'),
+            Command.FIND_CHILD_ELEMENT:
+                ('POST', '/session/$sessionId/element/$id/element'),
+            Command.FIND_CHILD_ELEMENTS:
+                ('POST', '/session/$sessionId/element/$id/elements'),
+            Command.CLICK_ELEMENT: ('POST', '/session/$sessionId/element/$id/click'),
+            Command.CLEAR_ELEMENT: ('POST', '/session/$sessionId/element/$id/clear'),
+            Command.SUBMIT_ELEMENT: ('POST', '/session/$sessionId/element/$id/submit'),
+            Command.GET_ELEMENT_TEXT: ('GET', '/session/$sessionId/element/$id/text'),
+            Command.SEND_KEYS_TO_ELEMENT:
+                ('POST', '/session/$sessionId/element/$id/value'),
+            Command.SEND_KEYS_TO_ACTIVE_ELEMENT:
+                ('POST', '/session/$sessionId/keys'),
+            Command.UPLOAD_FILE: ('POST', "/session/$sessionId/file"),
+            Command.GET_ELEMENT_VALUE:
+                ('GET', '/session/$sessionId/element/$id/value'),
+            Command.GET_ELEMENT_TAG_NAME:
+                ('GET', '/session/$sessionId/element/$id/name'),
+            Command.IS_ELEMENT_SELECTED:
+                ('GET', '/session/$sessionId/element/$id/selected'),
+            Command.SET_ELEMENT_SELECTED:
+                ('POST', '/session/$sessionId/element/$id/selected'),
+            Command.IS_ELEMENT_ENABLED:
+                ('GET', '/session/$sessionId/element/$id/enabled'),
+            Command.IS_ELEMENT_DISPLAYED:
+                ('GET', '/session/$sessionId/element/$id/displayed'),
+            Command.GET_ELEMENT_LOCATION:
+                ('GET', '/session/$sessionId/element/$id/location'),
+            Command.GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW:
+                ('GET', '/session/$sessionId/element/$id/location_in_view'),
+            Command.GET_ELEMENT_SIZE:
+                ('GET', '/session/$sessionId/element/$id/size'),
+            Command.GET_ELEMENT_RECT:
+                ('GET', '/session/$sessionId/element/$id/rect'),
+            Command.GET_ELEMENT_ATTRIBUTE:
+                ('GET', '/session/$sessionId/element/$id/attribute/$name'),
+            Command.GET_ELEMENT_PROPERTY:
+                ('GET', '/session/$sessionId/element/$id/property/$name'),
+            Command.GET_ALL_COOKIES: ('GET', '/session/$sessionId/cookie'),
+            Command.ADD_COOKIE: ('POST', '/session/$sessionId/cookie'),
+            Command.GET_COOKIE: ('GET', '/session/$sessionId/cookie/$name'),
+            Command.DELETE_ALL_COOKIES:
+                ('DELETE', '/session/$sessionId/cookie'),
+            Command.DELETE_COOKIE:
+                ('DELETE', '/session/$sessionId/cookie/$name'),
+            Command.SWITCH_TO_FRAME: ('POST', '/session/$sessionId/frame'),
+            Command.SWITCH_TO_PARENT_FRAME: ('POST', '/session/$sessionId/frame/parent'),
+            Command.SWITCH_TO_WINDOW: ('POST', '/session/$sessionId/window'),
+            Command.CLOSE: ('DELETE', '/session/$sessionId/window'),
+            Command.GET_ELEMENT_VALUE_OF_CSS_PROPERTY:
+                ('GET', '/session/$sessionId/element/$id/css/$propertyName'),
+            Command.IMPLICIT_WAIT:
+                ('POST', '/session/$sessionId/timeouts/implicit_wait'),
+            Command.EXECUTE_ASYNC_SCRIPT: ('POST', '/session/$sessionId/execute_async'),
+            Command.SET_SCRIPT_TIMEOUT:
+                ('POST', '/session/$sessionId/timeouts/async_script'),
+            Command.SET_TIMEOUTS:
+                ('POST', '/session/$sessionId/timeouts'),
+            Command.DISMISS_ALERT:
+                ('POST', '/session/$sessionId/dismiss_alert'),
+            Command.W3C_DISMISS_ALERT:
+                ('POST', '/session/$sessionId/alert/dismiss'),
+            Command.ACCEPT_ALERT:
+                ('POST', '/session/$sessionId/accept_alert'),
+            Command.W3C_ACCEPT_ALERT:
+                ('POST', '/session/$sessionId/alert/accept'),
+            Command.SET_ALERT_VALUE:
+                ('POST', '/session/$sessionId/alert_text'),
+            Command.W3C_SET_ALERT_VALUE:
+                ('POST', '/session/$sessionId/alert/text'),
+            Command.GET_ALERT_TEXT:
+                ('GET', '/session/$sessionId/alert_text'),
+            Command.W3C_GET_ALERT_TEXT:
+                ('GET', '/session/$sessionId/alert/text'),
+            Command.SET_ALERT_CREDENTIALS:
+                ('POST', '/session/$sessionId/alert/credentials'),
+            Command.CLICK:
+                ('POST', '/session/$sessionId/click'),
+            Command.W3C_ACTIONS:
+                ('POST', '/session/$sessionId/actions'),
+            Command.W3C_CLEAR_ACTIONS:
+                ('DELETE', '/session/$sessionId/actions'),
+            Command.DOUBLE_CLICK:
+                ('POST', '/session/$sessionId/doubleclick'),
+            Command.MOUSE_DOWN:
+                ('POST', '/session/$sessionId/buttondown'),
+            Command.MOUSE_UP:
+                ('POST', '/session/$sessionId/buttonup'),
+            Command.MOVE_TO:
+                ('POST', '/session/$sessionId/moveto'),
+            Command.GET_WINDOW_SIZE:
+                ('GET', '/session/$sessionId/window/$windowHandle/size'),
+            Command.SET_WINDOW_SIZE:
+                ('POST', '/session/$sessionId/window/$windowHandle/size'),
+            Command.GET_WINDOW_POSITION:
+                ('GET', '/session/$sessionId/window/$windowHandle/position'),
+            Command.SET_WINDOW_POSITION:
+                ('POST', '/session/$sessionId/window/$windowHandle/position'),
+            Command.SET_WINDOW_RECT:
+                ('POST', '/session/$sessionId/window/rect'),
+            Command.GET_WINDOW_RECT:
+                ('GET', '/session/$sessionId/window/rect'),
+            Command.MAXIMIZE_WINDOW:
+                ('POST', '/session/$sessionId/window/$windowHandle/maximize'),
+            Command.W3C_MAXIMIZE_WINDOW:
+                ('POST', '/session/$sessionId/window/maximize'),
+            Command.SET_SCREEN_ORIENTATION:
+                ('POST', '/session/$sessionId/orientation'),
+            Command.GET_SCREEN_ORIENTATION:
+                ('GET', '/session/$sessionId/orientation'),
+            Command.SINGLE_TAP:
+                ('POST', '/session/$sessionId/touch/click'),
+            Command.TOUCH_DOWN:
+                ('POST', '/session/$sessionId/touch/down'),
+            Command.TOUCH_UP:
+                ('POST', '/session/$sessionId/touch/up'),
+            Command.TOUCH_MOVE:
+                ('POST', '/session/$sessionId/touch/move'),
+            Command.TOUCH_SCROLL:
+                ('POST', '/session/$sessionId/touch/scroll'),
+            Command.DOUBLE_TAP:
+                ('POST', '/session/$sessionId/touch/doubleclick'),
+            Command.LONG_PRESS:
+                ('POST', '/session/$sessionId/touch/longclick'),
+            Command.FLICK:
+                ('POST', '/session/$sessionId/touch/flick'),
+            Command.EXECUTE_SQL:
+                ('POST', '/session/$sessionId/execute_sql'),
+            Command.GET_LOCATION:
+                ('GET', '/session/$sessionId/location'),
+            Command.SET_LOCATION:
+                ('POST', '/session/$sessionId/location'),
+            Command.GET_APP_CACHE:
+                ('GET', '/session/$sessionId/application_cache'),
+            Command.GET_APP_CACHE_STATUS:
+                ('GET', '/session/$sessionId/application_cache/status'),
+            Command.CLEAR_APP_CACHE:
+                ('DELETE', '/session/$sessionId/application_cache/clear'),
+            Command.GET_NETWORK_CONNECTION:
+                ('GET', '/session/$sessionId/network_connection'),
+            Command.SET_NETWORK_CONNECTION:
+                ('POST', '/session/$sessionId/network_connection'),
+            Command.GET_LOCAL_STORAGE_ITEM:
+                ('GET', '/session/$sessionId/local_storage/key/$key'),
+            Command.REMOVE_LOCAL_STORAGE_ITEM:
+                ('DELETE', '/session/$sessionId/local_storage/key/$key'),
+            Command.GET_LOCAL_STORAGE_KEYS:
+                ('GET', '/session/$sessionId/local_storage'),
+            Command.SET_LOCAL_STORAGE_ITEM:
+                ('POST', '/session/$sessionId/local_storage'),
+            Command.CLEAR_LOCAL_STORAGE:
+                ('DELETE', '/session/$sessionId/local_storage'),
+            Command.GET_LOCAL_STORAGE_SIZE:
+                ('GET', '/session/$sessionId/local_storage/size'),
+            Command.GET_SESSION_STORAGE_ITEM:
+                ('GET', '/session/$sessionId/session_storage/key/$key'),
+            Command.REMOVE_SESSION_STORAGE_ITEM:
+                ('DELETE', '/session/$sessionId/session_storage/key/$key'),
+            Command.GET_SESSION_STORAGE_KEYS:
+                ('GET', '/session/$sessionId/session_storage'),
+            Command.SET_SESSION_STORAGE_ITEM:
+                ('POST', '/session/$sessionId/session_storage'),
+            Command.CLEAR_SESSION_STORAGE:
+                ('DELETE', '/session/$sessionId/session_storage'),
+            Command.GET_SESSION_STORAGE_SIZE:
+                ('GET', '/session/$sessionId/session_storage/size'),
+            Command.GET_LOG:
+                ('POST', '/session/$sessionId/log'),
+            Command.GET_AVAILABLE_LOG_TYPES:
+                ('GET', '/session/$sessionId/log/types'),
+            Command.CURRENT_CONTEXT_HANDLE:
+                ('GET', '/session/$sessionId/context'),
+            Command.CONTEXT_HANDLES:
+                ('GET', '/session/$sessionId/contexts'),
+            Command.SWITCH_TO_CONTEXT:
+                ('POST', '/session/$sessionId/context'),
+            Command.FULLSCREEN_WINDOW:
+                ('POST', '/session/$sessionId/window/fullscreen'),
+            Command.MINIMIZE_WINDOW:
+                ('POST', '/session/$sessionId/window/minimize')
+        }
+
+    def execute(self, command, params):
+        """
+        Send a command to the remote server.
+
+        Any path subtitutions required for the URL mapped to the command should be
+        included in the command parameters.
+
+        :Args:
+         - command - A string specifying the command to execute.
+         - params - A dictionary of named parameters to send with the command as
+           its JSON payload.
+        """
+        command_info = self._commands[command]
+        assert command_info is not None, 'Unrecognised command %s' % command
+        path = string.Template(command_info[1]).substitute(params)
+        if hasattr(self, 'w3c') and self.w3c and isinstance(params, dict) and 'sessionId' in params:
+            del params['sessionId']
+        data = utils.dump_json(params)
+        url = '%s%s' % (self._url, path)
+        return self._request(command_info[0], url, body=data)
+
+    def _request(self, method, url, body=None):
+        """
+        Send an HTTP request to the remote server.
+
+        :Args:
+         - method - A string for the HTTP method to send the request with.
+         - url - A string for the URL to send the request to.
+         - body - A string for request body. Ignored unless method is POST or PUT.
+
+        :Returns:
+          A dictionary with the server's parsed JSON response.
+        """
+        LOGGER.debug('%s %s %s' % (method, url, body))
+
+        parsed_url = parse.urlparse(url)
+        headers = self.get_remote_connection_headers(parsed_url, self.keep_alive)
+        resp = None
+        if body and method != 'POST' and method != 'PUT':
+            body = None
+
+        if self.keep_alive:
+            resp = self._conn.request(method, url, body=body, headers=headers)
+
+            statuscode = resp.status
+        else:
+            http = urllib3.PoolManager(timeout=self._timeout)
+            resp = http.request(method, url, body=body, headers=headers)
+
+            statuscode = resp.status
+            if not hasattr(resp, 'getheader'):
+                if hasattr(resp.headers, 'getheader'):
+                    resp.getheader = lambda x: resp.headers.getheader(x)
+                elif hasattr(resp.headers, 'get'):
+                    resp.getheader = lambda x: resp.headers.get(x)
+
+        data = resp.data.decode('UTF-8')
+        try:
+            if 300 <= statuscode < 304:
+                return self._request('GET', resp.getheader('location'))
+            if 399 < statuscode <= 500:
+                return {'status': statuscode, 'value': data}
+            content_type = []
+            if resp.getheader('Content-Type') is not None:
+                content_type = resp.getheader('Content-Type').split(';')
+            if not any([x.startswith('image/png') for x in content_type]):
+
+                try:
+                    data = utils.load_json(data.strip())
+                except ValueError:
+                    if 199 < statuscode < 300:
+                        status = ErrorCode.SUCCESS
+                    else:
+                        status = ErrorCode.UNKNOWN_ERROR
+                    return {'status': status, 'value': data.strip()}
+
+                # Some of the drivers incorrectly return a response
+                # with no 'value' field when they should return null.
+                if 'value' not in data:
+                    data['value'] = None
+                return data
+            else:
+                data = {'status': 0, 'value': data}
+                return data
+        finally:
+            LOGGER.debug("Finished Request")
+            resp.close()

+ 134 - 0
selenium-3.141.0/build/lib/selenium/webdriver/remote/switch_to.py

@@ -0,0 +1,134 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from .command import Command
+from selenium.webdriver.common.alert import Alert
+from selenium.webdriver.common.by import By
+from selenium.common.exceptions import NoSuchElementException, NoSuchFrameException, NoSuchWindowException
+
+try:
+    basestring
+except NameError:
+    basestring = str
+
+
+class SwitchTo:
+    def __init__(self, driver):
+        self._driver = driver
+
+    @property
+    def active_element(self):
+        """
+        Returns the element with focus, or BODY if nothing has focus.
+
+        :Usage:
+            element = driver.switch_to.active_element
+        """
+        if self._driver.w3c:
+            return self._driver.execute(Command.W3C_GET_ACTIVE_ELEMENT)['value']
+        else:
+            return self._driver.execute(Command.GET_ACTIVE_ELEMENT)['value']
+
+    @property
+    def alert(self):
+        """
+        Switches focus to an alert on the page.
+
+        :Usage:
+            alert = driver.switch_to.alert
+        """
+        alert = Alert(self._driver)
+        alert.text
+        return alert
+
+    def default_content(self):
+        """
+        Switch focus to the default frame.
+
+        :Usage:
+            driver.switch_to.default_content()
+        """
+        self._driver.execute(Command.SWITCH_TO_FRAME, {'id': None})
+
+    def frame(self, frame_reference):
+        """
+        Switches focus to the specified frame, by index, name, or webelement.
+
+        :Args:
+         - frame_reference: The name of the window to switch to, an integer representing the index,
+                            or a webelement that is an (i)frame to switch to.
+
+        :Usage:
+            driver.switch_to.frame('frame_name')
+            driver.switch_to.frame(1)
+            driver.switch_to.frame(driver.find_elements_by_tag_name("iframe")[0])
+        """
+        if isinstance(frame_reference, basestring) and self._driver.w3c:
+            try:
+                frame_reference = self._driver.find_element(By.ID, frame_reference)
+            except NoSuchElementException:
+                try:
+                    frame_reference = self._driver.find_element(By.NAME, frame_reference)
+                except NoSuchElementException:
+                    raise NoSuchFrameException(frame_reference)
+
+        self._driver.execute(Command.SWITCH_TO_FRAME, {'id': frame_reference})
+
+    def parent_frame(self):
+        """
+        Switches focus to the parent context. If the current context is the top
+        level browsing context, the context remains unchanged.
+
+        :Usage:
+            driver.switch_to.parent_frame()
+        """
+        self._driver.execute(Command.SWITCH_TO_PARENT_FRAME)
+
+    def window(self, window_name):
+        """
+        Switches focus to the specified window.
+
+        :Args:
+         - window_name: The name or window handle of the window to switch to.
+
+        :Usage:
+            driver.switch_to.window('main')
+        """
+        if self._driver.w3c:
+            self._w3c_window(window_name)
+            return
+        data = {'name': window_name}
+        self._driver.execute(Command.SWITCH_TO_WINDOW, data)
+
+    def _w3c_window(self, window_name):
+        def send_handle(h):
+            self._driver.execute(Command.SWITCH_TO_WINDOW, {'handle': h})
+
+        try:
+            # Try using it as a handle first.
+            send_handle(window_name)
+        except NoSuchWindowException as e:
+            # Check every window to try to find the given window name.
+            original_handle = self._driver.current_window_handle
+            handles = self._driver.window_handles
+            for handle in handles:
+                send_handle(handle)
+                current_name = self._driver.execute_script('return window.name')
+                if window_name == current_name:
+                    return
+            send_handle(original_handle)
+            raise e

+ 90 - 0
selenium-3.141.0/build/lib/selenium/webdriver/remote/utils.py

@@ -0,0 +1,90 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import json
+import logging
+import os
+import tempfile
+import zipfile
+
+
+LOGGER = logging.getLogger(__name__)
+
+
+def format_json(json_struct):
+    return json.dumps(json_struct, indent=4)
+
+
+def dump_json(json_struct):
+    return json.dumps(json_struct)
+
+
+def load_json(s):
+    return json.loads(s)
+
+
+def unzip_to_temp_dir(zip_file_name):
+    """Unzip zipfile to a temporary directory.
+
+    The directory of the unzipped files is returned if success,
+    otherwise None is returned. """
+    if not zip_file_name or not os.path.exists(zip_file_name):
+        return None
+
+    zf = zipfile.ZipFile(zip_file_name)
+
+    if zf.testzip() is not None:
+        return None
+
+    # Unzip the files into a temporary directory
+    LOGGER.info("Extracting zipped file: %s" % zip_file_name)
+    tempdir = tempfile.mkdtemp()
+
+    try:
+        # Create directories that don't exist
+        for zip_name in zf.namelist():
+            # We have no knowledge on the os where the zipped file was
+            # created, so we restrict to zip files with paths without
+            # charactor "\" and "/".
+            name = (zip_name.replace("\\", os.path.sep).
+                    replace("/", os.path.sep))
+            dest = os.path.join(tempdir, name)
+            if (name.endswith(os.path.sep) and not os.path.exists(dest)):
+                os.mkdir(dest)
+                LOGGER.debug("Directory %s created." % dest)
+
+        # Copy files
+        for zip_name in zf.namelist():
+            # We have no knowledge on the os where the zipped file was
+            # created, so we restrict to zip files with paths without
+            # charactor "\" and "/".
+            name = (zip_name.replace("\\", os.path.sep).
+                    replace("/", os.path.sep))
+            dest = os.path.join(tempdir, name)
+            if not (name.endswith(os.path.sep)):
+                LOGGER.debug("Copying file %s......" % dest)
+                outfile = open(dest, 'wb')
+                outfile.write(zf.read(zip_name))
+                outfile.close()
+                LOGGER.debug("File %s copied." % dest)
+
+        LOGGER.info("Unzipped file can be found at %s" % tempdir)
+        return tempdir
+
+    except IOError as err:
+        LOGGER.error("Error in extracting webdriver.xpi: %s" % err)
+        return None

文件差异内容过多而无法显示
+ 1262 - 0
selenium-3.141.0/build/lib/selenium/webdriver/remote/webdriver.py


+ 708 - 0
selenium-3.141.0/build/lib/selenium/webdriver/remote/webelement.py

@@ -0,0 +1,708 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import base64
+import hashlib
+import os
+import pkgutil
+import warnings
+import zipfile
+
+from selenium.common.exceptions import WebDriverException
+from selenium.webdriver.common.by import By
+from selenium.webdriver.common.utils import keys_to_typing
+from .command import Command
+
+# Python 3 imports
+try:
+    str = basestring
+except NameError:
+    pass
+
+try:
+    from StringIO import StringIO as IOStream
+except ImportError:  # 3+
+    from io import BytesIO as IOStream
+
+# not relying on __package__ here as it can be `None` in some situations (see #4558)
+_pkg = '.'.join(__name__.split('.')[:-1])
+getAttribute_js = pkgutil.get_data(_pkg, 'getAttribute.js').decode('utf8')
+isDisplayed_js = pkgutil.get_data(_pkg, 'isDisplayed.js').decode('utf8')
+
+
+class WebElement(object):
+    """Represents a DOM element.
+
+    Generally, all interesting operations that interact with a document will be
+    performed through this interface.
+
+    All method calls will do a freshness check to ensure that the element
+    reference is still valid.  This essentially determines whether or not the
+    element is still attached to the DOM.  If this test fails, then an
+    ``StaleElementReferenceException`` is thrown, and all future calls to this
+    instance will fail."""
+
+    def __init__(self, parent, id_, w3c=False):
+        self._parent = parent
+        self._id = id_
+        self._w3c = w3c
+
+    def __repr__(self):
+        return '<{0.__module__}.{0.__name__} (session="{1}", element="{2}")>'.format(
+            type(self), self._parent.session_id, self._id)
+
+    @property
+    def tag_name(self):
+        """This element's ``tagName`` property."""
+        return self._execute(Command.GET_ELEMENT_TAG_NAME)['value']
+
+    @property
+    def text(self):
+        """The text of the element."""
+        return self._execute(Command.GET_ELEMENT_TEXT)['value']
+
+    def click(self):
+        """Clicks the element."""
+        self._execute(Command.CLICK_ELEMENT)
+
+    def submit(self):
+        """Submits a form."""
+        if self._w3c:
+            form = self.find_element(By.XPATH, "./ancestor-or-self::form")
+            self._parent.execute_script(
+                "var e = arguments[0].ownerDocument.createEvent('Event');"
+                "e.initEvent('submit', true, true);"
+                "if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }", form)
+        else:
+            self._execute(Command.SUBMIT_ELEMENT)
+
+    def clear(self):
+        """Clears the text if it's a text entry element."""
+        self._execute(Command.CLEAR_ELEMENT)
+
+    def get_property(self, name):
+        """
+        Gets the given property of the element.
+
+        :Args:
+            - name - Name of the property to retrieve.
+
+        Example::
+
+            text_length = target_element.get_property("text_length")
+        """
+        try:
+            return self._execute(Command.GET_ELEMENT_PROPERTY, {"name": name})["value"]
+        except WebDriverException:
+            # if we hit an end point that doesnt understand getElementProperty lets fake it
+            return self.parent.execute_script('return arguments[0][arguments[1]]', self, name)
+
+    def get_attribute(self, name):
+        """Gets the given attribute or property of the element.
+
+        This method will first try to return the value of a property with the
+        given name. If a property with that name doesn't exist, it returns the
+        value of the attribute with the same name. If there's no attribute with
+        that name, ``None`` is returned.
+
+        Values which are considered truthy, that is equals "true" or "false",
+        are returned as booleans.  All other non-``None`` values are returned
+        as strings.  For attributes or properties which do not exist, ``None``
+        is returned.
+
+        :Args:
+            - name - Name of the attribute/property to retrieve.
+
+        Example::
+
+            # Check if the "active" CSS class is applied to an element.
+            is_active = "active" in target_element.get_attribute("class")
+
+        """
+
+        attributeValue = ''
+        if self._w3c:
+            attributeValue = self.parent.execute_script(
+                "return (%s).apply(null, arguments);" % getAttribute_js,
+                self, name)
+        else:
+            resp = self._execute(Command.GET_ELEMENT_ATTRIBUTE, {'name': name})
+            attributeValue = resp.get('value')
+            if attributeValue is not None:
+                if name != 'value' and attributeValue.lower() in ('true', 'false'):
+                    attributeValue = attributeValue.lower()
+        return attributeValue
+
+    def is_selected(self):
+        """Returns whether the element is selected.
+
+        Can be used to check if a checkbox or radio button is selected.
+        """
+        return self._execute(Command.IS_ELEMENT_SELECTED)['value']
+
+    def is_enabled(self):
+        """Returns whether the element is enabled."""
+        return self._execute(Command.IS_ELEMENT_ENABLED)['value']
+
+    def find_element_by_id(self, id_):
+        """Finds element within this element's children by ID.
+
+        :Args:
+         - id\_ - ID of child element to locate.
+
+        :Returns:
+         - WebElement - the element if it was found
+
+        :Raises:
+         - NoSuchElementException - if the element wasn't found
+
+        :Usage:
+            foo_element = element.find_element_by_id('foo')
+        """
+        return self.find_element(by=By.ID, value=id_)
+
+    def find_elements_by_id(self, id_):
+        """Finds a list of elements within this element's children by ID.
+        Will return a list of webelements if found, or an empty list if not.
+
+        :Args:
+         - id\_ - Id of child element to find.
+
+        :Returns:
+         - list of WebElement - a list with elements if any was found.  An
+           empty list if not
+
+        :Usage:
+            elements = element.find_elements_by_id('foo')
+        """
+        return self.find_elements(by=By.ID, value=id_)
+
+    def find_element_by_name(self, name):
+        """Finds element within this element's children by name.
+
+        :Args:
+         - name - name property of the element to find.
+
+        :Returns:
+         - WebElement - the element if it was found
+
+        :Raises:
+         - NoSuchElementException - if the element wasn't found
+
+        :Usage:
+            element = element.find_element_by_name('foo')
+        """
+        return self.find_element(by=By.NAME, value=name)
+
+    def find_elements_by_name(self, name):
+        """Finds a list of elements within this element's children by name.
+
+        :Args:
+         - name - name property to search for.
+
+        :Returns:
+         - list of webelement - a list with elements if any was found.  an
+           empty list if not
+
+        :Usage:
+            elements = element.find_elements_by_name('foo')
+        """
+        return self.find_elements(by=By.NAME, value=name)
+
+    def find_element_by_link_text(self, link_text):
+        """Finds element within this element's children by visible link text.
+
+        :Args:
+         - link_text - Link text string to search for.
+
+        :Returns:
+         - WebElement - the element if it was found
+
+        :Raises:
+         - NoSuchElementException - if the element wasn't found
+
+        :Usage:
+            element = element.find_element_by_link_text('Sign In')
+        """
+        return self.find_element(by=By.LINK_TEXT, value=link_text)
+
+    def find_elements_by_link_text(self, link_text):
+        """Finds a list of elements within this element's children by visible link text.
+
+        :Args:
+         - link_text - Link text string to search for.
+
+        :Returns:
+         - list of webelement - a list with elements if any was found.  an
+           empty list if not
+
+        :Usage:
+            elements = element.find_elements_by_link_text('Sign In')
+        """
+        return self.find_elements(by=By.LINK_TEXT, value=link_text)
+
+    def find_element_by_partial_link_text(self, link_text):
+        """Finds element within this element's children by partially visible link text.
+
+        :Args:
+         - link_text: The text of the element to partially match on.
+
+        :Returns:
+         - WebElement - the element if it was found
+
+        :Raises:
+         - NoSuchElementException - if the element wasn't found
+
+        :Usage:
+            element = element.find_element_by_partial_link_text('Sign')
+        """
+        return self.find_element(by=By.PARTIAL_LINK_TEXT, value=link_text)
+
+    def find_elements_by_partial_link_text(self, link_text):
+        """Finds a list of elements within this element's children by link text.
+
+        :Args:
+         - link_text: The text of the element to partial match on.
+
+        :Returns:
+         - list of webelement - a list with elements if any was found.  an
+           empty list if not
+
+        :Usage:
+            elements = element.find_elements_by_partial_link_text('Sign')
+        """
+        return self.find_elements(by=By.PARTIAL_LINK_TEXT, value=link_text)
+
+    def find_element_by_tag_name(self, name):
+        """Finds element within this element's children by tag name.
+
+        :Args:
+         - name - name of html tag (eg: h1, a, span)
+
+        :Returns:
+         - WebElement - the element if it was found
+
+        :Raises:
+         - NoSuchElementException - if the element wasn't found
+
+        :Usage:
+            element = element.find_element_by_tag_name('h1')
+        """
+        return self.find_element(by=By.TAG_NAME, value=name)
+
+    def find_elements_by_tag_name(self, name):
+        """Finds a list of elements within this element's children by tag name.
+
+        :Args:
+         - name - name of html tag (eg: h1, a, span)
+
+        :Returns:
+         - list of WebElement - a list with elements if any was found.  An
+           empty list if not
+
+        :Usage:
+            elements = element.find_elements_by_tag_name('h1')
+        """
+        return self.find_elements(by=By.TAG_NAME, value=name)
+
+    def find_element_by_xpath(self, xpath):
+        """Finds element by xpath.
+
+        :Args:
+         - xpath - xpath of element to locate.  "//input[@class='myelement']"
+
+        Note: The base path will be relative to this element's location.
+
+        This will select the first link under this element.
+
+        ::
+
+            myelement.find_element_by_xpath(".//a")
+
+        However, this will select the first link on the page.
+
+        ::
+
+            myelement.find_element_by_xpath("//a")
+
+        :Returns:
+         - WebElement - the element if it was found
+
+        :Raises:
+         - NoSuchElementException - if the element wasn't found
+
+        :Usage:
+            element = element.find_element_by_xpath('//div/td[1]')
+        """
+        return self.find_element(by=By.XPATH, value=xpath)
+
+    def find_elements_by_xpath(self, xpath):
+        """Finds elements within the element by xpath.
+
+        :Args:
+         - xpath - xpath locator string.
+
+        Note: The base path will be relative to this element's location.
+
+        This will select all links under this element.
+
+        ::
+
+            myelement.find_elements_by_xpath(".//a")
+
+        However, this will select all links in the page itself.
+
+        ::
+
+            myelement.find_elements_by_xpath("//a")
+
+        :Returns:
+         - list of WebElement - a list with elements if any was found.  An
+           empty list if not
+
+        :Usage:
+            elements = element.find_elements_by_xpath("//div[contains(@class, 'foo')]")
+
+        """
+        return self.find_elements(by=By.XPATH, value=xpath)
+
+    def find_element_by_class_name(self, name):
+        """Finds element within this element's children by class name.
+
+        :Args:
+         - name: The class name of the element to find.
+
+        :Returns:
+         - WebElement - the element if it was found
+
+        :Raises:
+         - NoSuchElementException - if the element wasn't found
+
+        :Usage:
+            element = element.find_element_by_class_name('foo')
+        """
+        return self.find_element(by=By.CLASS_NAME, value=name)
+
+    def find_elements_by_class_name(self, name):
+        """Finds a list of elements within this element's children by class name.
+
+        :Args:
+         - name: The class name of the elements to find.
+
+        :Returns:
+         - list of WebElement - a list with elements if any was found.  An
+           empty list if not
+
+        :Usage:
+            elements = element.find_elements_by_class_name('foo')
+        """
+        return self.find_elements(by=By.CLASS_NAME, value=name)
+
+    def find_element_by_css_selector(self, css_selector):
+        """Finds element within this element's children by CSS selector.
+
+        :Args:
+         - css_selector - CSS selector string, ex: 'a.nav#home'
+
+        :Returns:
+         - WebElement - the element if it was found
+
+        :Raises:
+         - NoSuchElementException - if the element wasn't found
+
+        :Usage:
+            element = element.find_element_by_css_selector('#foo')
+        """
+        return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
+
+    def find_elements_by_css_selector(self, css_selector):
+        """Finds a list of elements within this element's children by CSS selector.
+
+        :Args:
+         - css_selector - CSS selector string, ex: 'a.nav#home'
+
+        :Returns:
+         - list of WebElement - a list with elements if any was found.  An
+           empty list if not
+
+        :Usage:
+            elements = element.find_elements_by_css_selector('.foo')
+        """
+        return self.find_elements(by=By.CSS_SELECTOR, value=css_selector)
+
+    def send_keys(self, *value):
+        """Simulates typing into the element.
+
+        :Args:
+            - value - A string for typing, or setting form fields.  For setting
+              file inputs, this could be a local file path.
+
+        Use this to send simple key events or to fill out form fields::
+
+            form_textfield = driver.find_element_by_name('username')
+            form_textfield.send_keys("admin")
+
+        This can also be used to set file inputs.
+
+        ::
+
+            file_input = driver.find_element_by_name('profilePic')
+            file_input.send_keys("path/to/profilepic.gif")
+            # Generally it's better to wrap the file path in one of the methods
+            # in os.path to return the actual path to support cross OS testing.
+            # file_input.send_keys(os.path.abspath("path/to/profilepic.gif"))
+
+        """
+        # transfer file to another machine only if remote driver is used
+        # the same behaviour as for java binding
+        if self.parent._is_remote:
+            local_file = self.parent.file_detector.is_local_file(*value)
+            if local_file is not None:
+                value = self._upload(local_file)
+
+        self._execute(Command.SEND_KEYS_TO_ELEMENT,
+                      {'text': "".join(keys_to_typing(value)),
+                       'value': keys_to_typing(value)})
+
+    # RenderedWebElement Items
+    def is_displayed(self):
+        """Whether the element is visible to a user."""
+        # Only go into this conditional for browsers that don't use the atom themselves
+        if self._w3c:
+            return self.parent.execute_script(
+                "return (%s).apply(null, arguments);" % isDisplayed_js,
+                self)
+        else:
+            return self._execute(Command.IS_ELEMENT_DISPLAYED)['value']
+
+    @property
+    def location_once_scrolled_into_view(self):
+        """THIS PROPERTY MAY CHANGE WITHOUT WARNING. Use this to discover
+        where on the screen an element is so that we can click it. This method
+        should cause the element to be scrolled into view.
+
+        Returns the top lefthand corner location on the screen, or ``None`` if
+        the element is not visible.
+
+        """
+        if self._w3c:
+            old_loc = self._execute(Command.W3C_EXECUTE_SCRIPT, {
+                'script': "arguments[0].scrollIntoView(true); return arguments[0].getBoundingClientRect()",
+                'args': [self]})['value']
+            return {"x": round(old_loc['x']),
+                    "y": round(old_loc['y'])}
+        else:
+            return self._execute(Command.GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW)['value']
+
+    @property
+    def size(self):
+        """The size of the element."""
+        size = {}
+        if self._w3c:
+            size = self._execute(Command.GET_ELEMENT_RECT)['value']
+        else:
+            size = self._execute(Command.GET_ELEMENT_SIZE)['value']
+        new_size = {"height": size["height"],
+                    "width": size["width"]}
+        return new_size
+
+    def value_of_css_property(self, property_name):
+        """The value of a CSS property."""
+        return self._execute(Command.GET_ELEMENT_VALUE_OF_CSS_PROPERTY, {
+            'propertyName': property_name})['value']
+
+    @property
+    def location(self):
+        """The location of the element in the renderable canvas."""
+        if self._w3c:
+            old_loc = self._execute(Command.GET_ELEMENT_RECT)['value']
+        else:
+            old_loc = self._execute(Command.GET_ELEMENT_LOCATION)['value']
+        new_loc = {"x": round(old_loc['x']),
+                   "y": round(old_loc['y'])}
+        return new_loc
+
+    @property
+    def rect(self):
+        """A dictionary with the size and location of the element."""
+        if self._w3c:
+            return self._execute(Command.GET_ELEMENT_RECT)['value']
+        else:
+            rect = self.size.copy()
+            rect.update(self.location)
+            return rect
+
+    @property
+    def screenshot_as_base64(self):
+        """
+        Gets the screenshot of the current element as a base64 encoded string.
+
+        :Usage:
+            img_b64 = element.screenshot_as_base64
+        """
+        return self._execute(Command.ELEMENT_SCREENSHOT)['value']
+
+    @property
+    def screenshot_as_png(self):
+        """
+        Gets the screenshot of the current element as a binary data.
+
+        :Usage:
+            element_png = element.screenshot_as_png
+        """
+        return base64.b64decode(self.screenshot_as_base64.encode('ascii'))
+
+    def screenshot(self, filename):
+        """
+        Saves a screenshot of the current element to a PNG image file. Returns
+           False if there is any IOError, else returns True. Use full paths in
+           your filename.
+
+        :Args:
+         - filename: The full path you wish to save your screenshot to. This
+           should end with a `.png` extension.
+
+        :Usage:
+            element.screenshot('/Screenshots/foo.png')
+        """
+        if not filename.lower().endswith('.png'):
+            warnings.warn("name used for saved screenshot does not match file "
+                          "type. It should end with a `.png` extension", UserWarning)
+        png = self.screenshot_as_png
+        try:
+            with open(filename, 'wb') as f:
+                f.write(png)
+        except IOError:
+            return False
+        finally:
+            del png
+        return True
+
+    @property
+    def parent(self):
+        """Internal reference to the WebDriver instance this element was found from."""
+        return self._parent
+
+    @property
+    def id(self):
+        """Internal ID used by selenium.
+
+        This is mainly for internal use. Simple use cases such as checking if 2
+        webelements refer to the same element, can be done using ``==``::
+
+            if element1 == element2:
+                print("These 2 are equal")
+
+        """
+        return self._id
+
+    def __eq__(self, element):
+        return hasattr(element, 'id') and self._id == element.id
+
+    def __ne__(self, element):
+        return not self.__eq__(element)
+
+    # Private Methods
+    def _execute(self, command, params=None):
+        """Executes a command against the underlying HTML element.
+
+        Args:
+          command: The name of the command to _execute as a string.
+          params: A dictionary of named parameters to send with the command.
+
+        Returns:
+          The command's JSON response loaded into a dictionary object.
+        """
+        if not params:
+            params = {}
+        params['id'] = self._id
+        return self._parent.execute(command, params)
+
+    def find_element(self, by=By.ID, value=None):
+        """
+        Find an element given a By strategy and locator. Prefer the find_element_by_* methods when
+        possible.
+
+        :Usage:
+            element = element.find_element(By.ID, 'foo')
+
+        :rtype: WebElement
+        """
+        if self._w3c:
+            if by == By.ID:
+                by = By.CSS_SELECTOR
+                value = '[id="%s"]' % value
+            elif by == By.TAG_NAME:
+                by = By.CSS_SELECTOR
+            elif by == By.CLASS_NAME:
+                by = By.CSS_SELECTOR
+                value = ".%s" % value
+            elif by == By.NAME:
+                by = By.CSS_SELECTOR
+                value = '[name="%s"]' % value
+
+        return self._execute(Command.FIND_CHILD_ELEMENT,
+                             {"using": by, "value": value})['value']
+
+    def find_elements(self, by=By.ID, value=None):
+        """
+        Find elements given a By strategy and locator. Prefer the find_elements_by_* methods when
+        possible.
+
+        :Usage:
+            element = element.find_elements(By.CLASS_NAME, 'foo')
+
+        :rtype: list of WebElement
+        """
+        if self._w3c:
+            if by == By.ID:
+                by = By.CSS_SELECTOR
+                value = '[id="%s"]' % value
+            elif by == By.TAG_NAME:
+                by = By.CSS_SELECTOR
+            elif by == By.CLASS_NAME:
+                by = By.CSS_SELECTOR
+                value = ".%s" % value
+            elif by == By.NAME:
+                by = By.CSS_SELECTOR
+                value = '[name="%s"]' % value
+
+        return self._execute(Command.FIND_CHILD_ELEMENTS,
+                             {"using": by, "value": value})['value']
+
+    def __hash__(self):
+        return int(hashlib.md5(self._id.encode('utf-8')).hexdigest(), 16)
+
+    def _upload(self, filename):
+        fp = IOStream()
+        zipped = zipfile.ZipFile(fp, 'w', zipfile.ZIP_DEFLATED)
+        zipped.write(filename, os.path.split(filename)[1])
+        zipped.close()
+        content = base64.encodestring(fp.getvalue())
+        if not isinstance(content, str):
+            content = content.decode('utf-8')
+        try:
+            return self._execute(Command.UPLOAD_FILE, {'file': content})['value']
+        except WebDriverException as e:
+            if "Unrecognized command: POST" in e.__str__():
+                return filename
+            elif "Command not found: POST " in e.__str__():
+                return filename
+            elif '{"status":405,"value":["GET","HEAD","DELETE"]}' in e.__str__():
+                return filename
+            else:
+                raise e

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/safari/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 28 - 0
selenium-3.141.0/build/lib/selenium/webdriver/safari/permissions.py

@@ -0,0 +1,28 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+The Permission implementation.
+"""
+
+
+class Permission(object):
+    """
+    Set of supported permissions.
+    """
+
+    GET_USER_MEDIA = "getUserMedia"

+ 27 - 0
selenium-3.141.0/build/lib/selenium/webdriver/safari/remote_connection.py

@@ -0,0 +1,27 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.remote.remote_connection import RemoteConnection
+
+
+class SafariRemoteConnection(RemoteConnection):
+    def __init__(self, remote_server_addr, keep_alive=True):
+        RemoteConnection.__init__(self, remote_server_addr, keep_alive)
+
+        self._commands["GET_PERMISSIONS"] = ('GET', '/session/$sessionId/apple/permissions')
+        self._commands["SET_PERMISSIONS"] = ('POST', '/session/$sessionId/apple/permissions')
+        self._commands["ATTACH_DEBUGGER"] = ('POST', '/session/$sessionId/apple/attach_debugger')

+ 64 - 0
selenium-3.141.0/build/lib/selenium/webdriver/safari/service.py

@@ -0,0 +1,64 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import os
+from selenium.webdriver.common import service, utils
+from subprocess import PIPE
+
+
+class Service(service.Service):
+    """
+    Object that manages the starting and stopping of the SafariDriver
+    """
+
+    def __init__(self, executable_path, port=0, quiet=False, service_args=None):
+        """
+        Creates a new instance of the Service
+
+        :Args:
+         - executable_path : Path to the SafariDriver
+         - port : Port the service is running on
+         - quiet : Suppress driver stdout and stderr
+         - service_args : List of args to pass to the safaridriver service """
+
+        if not os.path.exists(executable_path):
+            if "Safari Technology Preview" in executable_path:
+                message = "Safari Technology Preview does not seem to be installed. You can download it at https://developer.apple.com/safari/download/."
+            else:
+                message = "SafariDriver was not found; are you running Safari 10 or later? You can download Safari at https://developer.apple.com/safari/download/."
+            raise Exception(message)
+
+        if port == 0:
+            port = utils.free_port()
+
+        self.service_args = service_args or []
+
+        self.quiet = quiet
+        log = PIPE
+        if quiet:
+            log = open(os.devnull, 'w')
+        service.Service.__init__(self, executable_path, port, log)
+
+    def command_line_args(self):
+        return ["-p", "%s" % self.port] + self.service_args
+
+    @property
+    def service_url(self):
+        """
+        Gets the url of the SafariDriver Service
+        """
+        return "http://localhost:%d" % self.port

+ 113 - 0
selenium-3.141.0/build/lib/selenium/webdriver/safari/webdriver.py

@@ -0,0 +1,113 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from selenium.common.exceptions import WebDriverException
+
+try:
+    import http.client as http_client
+except ImportError:
+    import httplib as http_client
+
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
+from .service import Service
+from .remote_connection import SafariRemoteConnection
+
+
+class WebDriver(RemoteWebDriver):
+    """
+    Controls the SafariDriver and allows you to drive the browser.
+
+    """
+
+    def __init__(self, port=0, executable_path="/usr/bin/safaridriver", reuse_service=False,
+                 desired_capabilities=DesiredCapabilities.SAFARI, quiet=False,
+                 keep_alive=True, service_args=None):
+        """
+
+        Creates a new Safari driver instance and launches or finds a running safaridriver service.
+
+        :Args:
+         - port - The port on which the safaridriver service should listen for new connections. If zero, a free port will be found.
+         - executable_path - Path to a custom safaridriver executable to be used. If absent, /usr/bin/safaridriver is used.
+         - reuse_service - If True, do not spawn a safaridriver instance; instead, connect to an already-running service that was launched externally.
+         - desired_capabilities: Dictionary object with desired capabilities (Can be used to provide various Safari switches).
+         - quiet - If True, the driver's stdout and stderr is suppressed.
+         - keep_alive - Whether to configure SafariRemoteConnection to use
+             HTTP keep-alive. Defaults to False.
+         - service_args : List of args to pass to the safaridriver service
+        """
+
+        self._reuse_service = reuse_service
+        self.service = Service(executable_path, port=port, quiet=quiet, service_args=service_args)
+        if not reuse_service:
+            self.service.start()
+
+        executor = SafariRemoteConnection(remote_server_addr=self.service.service_url,
+                                          keep_alive=keep_alive)
+
+        RemoteWebDriver.__init__(
+            self,
+            command_executor=executor,
+            desired_capabilities=desired_capabilities)
+
+        self._is_remote = False
+
+    def quit(self):
+        """
+        Closes the browser and shuts down the SafariDriver executable
+        that is started when starting the SafariDriver
+        """
+        try:
+            RemoteWebDriver.quit(self)
+        except http_client.BadStatusLine:
+            pass
+        finally:
+            if not self._reuse_service:
+                self.service.stop()
+
+    # safaridriver extension commands. The canonical command support matrix is here:
+    # https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/WebDriverEndpointDoc/Commands/Commands.html
+
+    # First available in Safari 11.1 and Safari Technology Preview 41.
+    def set_permission(self, permission, value):
+        if not isinstance(value, bool):
+            raise WebDriverException("Value of a session permission must be set to True or False.")
+
+        payload = {}
+        payload[permission] = value
+        self.execute("SET_PERMISSIONS", {"permissions": payload})
+
+    # First available in Safari 11.1 and Safari Technology Preview 41.
+    def get_permission(self, permission):
+        payload = self.execute("GET_PERMISSIONS")["value"]
+        permissions = payload["permissions"]
+        if not permissions:
+            return None
+
+        if permission not in permissions:
+            return None
+
+        value = permissions[permission]
+        if not isinstance(value, bool):
+            return None
+
+        return value
+
+    # First available in Safari 11.1 and Safari Technology Preview 42.
+    def debug(self):
+        self.execute("ATTACH_DEBUGGER")
+        self.execute_script("debugger;")

+ 16 - 0
selenium-3.141.0/build/lib/selenium/webdriver/support/__init__.py

@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.

+ 79 - 0
selenium-3.141.0/build/lib/selenium/webdriver/support/abstract_event_listener.py

@@ -0,0 +1,79 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+class AbstractEventListener(object):
+    """
+    Event listener must subclass and implement this fully or partially
+    """
+
+    def before_navigate_to(self, url, driver):
+        pass
+
+    def after_navigate_to(self, url, driver):
+        pass
+
+    def before_navigate_back(self, driver):
+        pass
+
+    def after_navigate_back(self, driver):
+        pass
+
+    def before_navigate_forward(self, driver):
+        pass
+
+    def after_navigate_forward(self, driver):
+        pass
+
+    def before_find(self, by, value, driver):
+        pass
+
+    def after_find(self, by, value, driver):
+        pass
+
+    def before_click(self, element, driver):
+        pass
+
+    def after_click(self, element, driver):
+        pass
+
+    def before_change_value_of(self, element, driver):
+        pass
+
+    def after_change_value_of(self, element, driver):
+        pass
+
+    def before_execute_script(self, script, driver):
+        pass
+
+    def after_execute_script(self, script, driver):
+        pass
+
+    def before_close(self, driver):
+        pass
+
+    def after_close(self, driver):
+        pass
+
+    def before_quit(self, driver):
+        pass
+
+    def after_quit(self, driver):
+        pass
+
+    def on_exception(self, exception, driver):
+        pass

+ 310 - 0
selenium-3.141.0/build/lib/selenium/webdriver/support/color.py

@@ -0,0 +1,310 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+RGB_PATTERN = r"^\s*rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)\s*$"
+RGB_PCT_PATTERN = r"^\s*rgb\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*\)\s*$"
+RGBA_PATTERN = r"^\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0\.\d+)\s*\)\s*$"
+RGBA_PCT_PATTERN = r"^\s*rgba\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(0|1|0\.\d+)\s*\)\s*$"
+HEX_PATTERN = r"#([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})"
+HEX3_PATTERN = r"#([A-Fa-f0-9])([A-Fa-f0-9])([A-Fa-f0-9])"
+HSL_PATTERN = r"^\s*hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*\)\s*$"
+HSLA_PATTERN = r"^\s*hsla\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*,\s*(0|1|0\.\d+)\s*\)\s*$"
+
+
+class Color(object):
+    """
+    Color conversion support class
+
+    Example:
+
+    .. code-block:: python
+
+        from selenium.webdriver.support.color import Color
+
+        print(Color.from_string('#00ff33').rgba)
+        print(Color.from_string('rgb(1, 255, 3)').hex)
+        print(Color.from_string('blue').rgba)
+    """
+
+    @staticmethod
+    def from_string(str_):
+        import re
+
+        class Matcher(object):
+            def __init__(self):
+                self.match_obj = None
+
+            def match(self, pattern, str_):
+                self.match_obj = re.match(pattern, str_)
+                return self.match_obj
+
+            @property
+            def groups(self):
+                return () if self.match_obj is None else self.match_obj.groups()
+
+        m = Matcher()
+
+        if m.match(RGB_PATTERN, str_):
+            return Color(*m.groups)
+        elif m.match(RGB_PCT_PATTERN, str_):
+            rgb = tuple([float(each) / 100 * 255 for each in m.groups])
+            return Color(*rgb)
+        elif m.match(RGBA_PATTERN, str_):
+            return Color(*m.groups)
+        elif m.match(RGBA_PCT_PATTERN, str_):
+            rgba = tuple([float(each) / 100 * 255 for each in m.groups[:3]] + [m.groups[3]])
+            return Color(*rgba)
+        elif m.match(HEX_PATTERN, str_):
+            rgb = tuple([int(each, 16) for each in m.groups])
+            return Color(*rgb)
+        elif m.match(HEX3_PATTERN, str_):
+            rgb = tuple([int(each * 2, 16) for each in m.groups])
+            return Color(*rgb)
+        elif m.match(HSL_PATTERN, str_) or m.match(HSLA_PATTERN, str_):
+            return Color._from_hsl(*m.groups)
+        elif str_.upper() in Colors.keys():
+            return Colors[str_.upper()]
+        else:
+            raise ValueError("Could not convert %s into color" % str_)
+
+    @staticmethod
+    def _from_hsl(h, s, l, a=1):
+        h = float(h) / 360
+        s = float(s) / 100
+        l = float(l) / 100
+
+        if s == 0:
+            r = l
+            g = r
+            b = r
+        else:
+            luminocity2 = l * (1 + s) if l < 0.5 else l + s - l * s
+            luminocity1 = 2 * l - luminocity2
+
+            def hue_to_rgb(lum1, lum2, hue):
+                if hue < 0.0:
+                    hue += 1
+                if hue > 1.0:
+                    hue -= 1
+
+                if hue < 1.0 / 6.0:
+                    return (lum1 + (lum2 - lum1) * 6.0 * hue)
+                elif hue < 1.0 / 2.0:
+                    return lum2
+                elif hue < 2.0 / 3.0:
+                    return lum1 + (lum2 - lum1) * ((2.0 / 3.0) - hue) * 6.0
+                else:
+                    return lum1
+
+            r = hue_to_rgb(luminocity1, luminocity2, h + 1.0 / 3.0)
+            g = hue_to_rgb(luminocity1, luminocity2, h)
+            b = hue_to_rgb(luminocity1, luminocity2, h - 1.0 / 3.0)
+
+        return Color(round(r * 255), round(g * 255), round(b * 255), a)
+
+    def __init__(self, red, green, blue, alpha=1):
+        self.red = int(red)
+        self.green = int(green)
+        self.blue = int(blue)
+        self.alpha = "1" if float(alpha) == 1 else str(float(alpha) or 0)
+
+    @property
+    def rgb(self):
+        return "rgb(%d, %d, %d)" % (self.red, self.green, self.blue)
+
+    @property
+    def rgba(self):
+        return "rgba(%d, %d, %d, %s)" % (self.red, self.green, self.blue, self.alpha)
+
+    @property
+    def hex(self):
+        return "#%02x%02x%02x" % (self.red, self.green, self.blue)
+
+    def __eq__(self, other):
+        if isinstance(other, Color):
+            return self.rgba == other.rgba
+        return NotImplemented
+
+    def __ne__(self, other):
+        result = self.__eq__(other)
+        if result is NotImplemented:
+            return result
+        return not result
+
+    def __hash__(self):
+        return hash((self.red, self.green, self.blue, self.alpha))
+
+    def __repr__(self):
+        return "Color(red=%d, green=%d, blue=%d, alpha=%s)" % (self.red, self.green, self.blue, self.alpha)
+
+    def __str__(self):
+        return "Color: %s" % self.rgba
+
+
+# Basic, extended and transparent colour keywords as defined by the W3C HTML4 spec
+# See http://www.w3.org/TR/css3-color/#html4
+Colors = {
+    "TRANSPARENT": Color(0, 0, 0, 0),
+    "ALICEBLUE": Color(240, 248, 255),
+    "ANTIQUEWHITE": Color(250, 235, 215),
+    "AQUA": Color(0, 255, 255),
+    "AQUAMARINE": Color(127, 255, 212),
+    "AZURE": Color(240, 255, 255),
+    "BEIGE": Color(245, 245, 220),
+    "BISQUE": Color(255, 228, 196),
+    "BLACK": Color(0, 0, 0),
+    "BLANCHEDALMOND": Color(255, 235, 205),
+    "BLUE": Color(0, 0, 255),
+    "BLUEVIOLET": Color(138, 43, 226),
+    "BROWN": Color(165, 42, 42),
+    "BURLYWOOD": Color(222, 184, 135),
+    "CADETBLUE": Color(95, 158, 160),
+    "CHARTREUSE": Color(127, 255, 0),
+    "CHOCOLATE": Color(210, 105, 30),
+    "CORAL": Color(255, 127, 80),
+    "CORNFLOWERBLUE": Color(100, 149, 237),
+    "CORNSILK": Color(255, 248, 220),
+    "CRIMSON": Color(220, 20, 60),
+    "CYAN": Color(0, 255, 255),
+    "DARKBLUE": Color(0, 0, 139),
+    "DARKCYAN": Color(0, 139, 139),
+    "DARKGOLDENROD": Color(184, 134, 11),
+    "DARKGRAY": Color(169, 169, 169),
+    "DARKGREEN": Color(0, 100, 0),
+    "DARKGREY": Color(169, 169, 169),
+    "DARKKHAKI": Color(189, 183, 107),
+    "DARKMAGENTA": Color(139, 0, 139),
+    "DARKOLIVEGREEN": Color(85, 107, 47),
+    "DARKORANGE": Color(255, 140, 0),
+    "DARKORCHID": Color(153, 50, 204),
+    "DARKRED": Color(139, 0, 0),
+    "DARKSALMON": Color(233, 150, 122),
+    "DARKSEAGREEN": Color(143, 188, 143),
+    "DARKSLATEBLUE": Color(72, 61, 139),
+    "DARKSLATEGRAY": Color(47, 79, 79),
+    "DARKSLATEGREY": Color(47, 79, 79),
+    "DARKTURQUOISE": Color(0, 206, 209),
+    "DARKVIOLET": Color(148, 0, 211),
+    "DEEPPINK": Color(255, 20, 147),
+    "DEEPSKYBLUE": Color(0, 191, 255),
+    "DIMGRAY": Color(105, 105, 105),
+    "DIMGREY": Color(105, 105, 105),
+    "DODGERBLUE": Color(30, 144, 255),
+    "FIREBRICK": Color(178, 34, 34),
+    "FLORALWHITE": Color(255, 250, 240),
+    "FORESTGREEN": Color(34, 139, 34),
+    "FUCHSIA": Color(255, 0, 255),
+    "GAINSBORO": Color(220, 220, 220),
+    "GHOSTWHITE": Color(248, 248, 255),
+    "GOLD": Color(255, 215, 0),
+    "GOLDENROD": Color(218, 165, 32),
+    "GRAY": Color(128, 128, 128),
+    "GREY": Color(128, 128, 128),
+    "GREEN": Color(0, 128, 0),
+    "GREENYELLOW": Color(173, 255, 47),
+    "HONEYDEW": Color(240, 255, 240),
+    "HOTPINK": Color(255, 105, 180),
+    "INDIANRED": Color(205, 92, 92),
+    "INDIGO": Color(75, 0, 130),
+    "IVORY": Color(255, 255, 240),
+    "KHAKI": Color(240, 230, 140),
+    "LAVENDER": Color(230, 230, 250),
+    "LAVENDERBLUSH": Color(255, 240, 245),
+    "LAWNGREEN": Color(124, 252, 0),
+    "LEMONCHIFFON": Color(255, 250, 205),
+    "LIGHTBLUE": Color(173, 216, 230),
+    "LIGHTCORAL": Color(240, 128, 128),
+    "LIGHTCYAN": Color(224, 255, 255),
+    "LIGHTGOLDENRODYELLOW": Color(250, 250, 210),
+    "LIGHTGRAY": Color(211, 211, 211),
+    "LIGHTGREEN": Color(144, 238, 144),
+    "LIGHTGREY": Color(211, 211, 211),
+    "LIGHTPINK": Color(255, 182, 193),
+    "LIGHTSALMON": Color(255, 160, 122),
+    "LIGHTSEAGREEN": Color(32, 178, 170),
+    "LIGHTSKYBLUE": Color(135, 206, 250),
+    "LIGHTSLATEGRAY": Color(119, 136, 153),
+    "LIGHTSLATEGREY": Color(119, 136, 153),
+    "LIGHTSTEELBLUE": Color(176, 196, 222),
+    "LIGHTYELLOW": Color(255, 255, 224),
+    "LIME": Color(0, 255, 0),
+    "LIMEGREEN": Color(50, 205, 50),
+    "LINEN": Color(250, 240, 230),
+    "MAGENTA": Color(255, 0, 255),
+    "MAROON": Color(128, 0, 0),
+    "MEDIUMAQUAMARINE": Color(102, 205, 170),
+    "MEDIUMBLUE": Color(0, 0, 205),
+    "MEDIUMORCHID": Color(186, 85, 211),
+    "MEDIUMPURPLE": Color(147, 112, 219),
+    "MEDIUMSEAGREEN": Color(60, 179, 113),
+    "MEDIUMSLATEBLUE": Color(123, 104, 238),
+    "MEDIUMSPRINGGREEN": Color(0, 250, 154),
+    "MEDIUMTURQUOISE": Color(72, 209, 204),
+    "MEDIUMVIOLETRED": Color(199, 21, 133),
+    "MIDNIGHTBLUE": Color(25, 25, 112),
+    "MINTCREAM": Color(245, 255, 250),
+    "MISTYROSE": Color(255, 228, 225),
+    "MOCCASIN": Color(255, 228, 181),
+    "NAVAJOWHITE": Color(255, 222, 173),
+    "NAVY": Color(0, 0, 128),
+    "OLDLACE": Color(253, 245, 230),
+    "OLIVE": Color(128, 128, 0),
+    "OLIVEDRAB": Color(107, 142, 35),
+    "ORANGE": Color(255, 165, 0),
+    "ORANGERED": Color(255, 69, 0),
+    "ORCHID": Color(218, 112, 214),
+    "PALEGOLDENROD": Color(238, 232, 170),
+    "PALEGREEN": Color(152, 251, 152),
+    "PALETURQUOISE": Color(175, 238, 238),
+    "PALEVIOLETRED": Color(219, 112, 147),
+    "PAPAYAWHIP": Color(255, 239, 213),
+    "PEACHPUFF": Color(255, 218, 185),
+    "PERU": Color(205, 133, 63),
+    "PINK": Color(255, 192, 203),
+    "PLUM": Color(221, 160, 221),
+    "POWDERBLUE": Color(176, 224, 230),
+    "PURPLE": Color(128, 0, 128),
+    "REBECCAPURPLE": Color(128, 51, 153),
+    "RED": Color(255, 0, 0),
+    "ROSYBROWN": Color(188, 143, 143),
+    "ROYALBLUE": Color(65, 105, 225),
+    "SADDLEBROWN": Color(139, 69, 19),
+    "SALMON": Color(250, 128, 114),
+    "SANDYBROWN": Color(244, 164, 96),
+    "SEAGREEN": Color(46, 139, 87),
+    "SEASHELL": Color(255, 245, 238),
+    "SIENNA": Color(160, 82, 45),
+    "SILVER": Color(192, 192, 192),
+    "SKYBLUE": Color(135, 206, 235),
+    "SLATEBLUE": Color(106, 90, 205),
+    "SLATEGRAY": Color(112, 128, 144),
+    "SLATEGREY": Color(112, 128, 144),
+    "SNOW": Color(255, 250, 250),
+    "SPRINGGREEN": Color(0, 255, 127),
+    "STEELBLUE": Color(70, 130, 180),
+    "TAN": Color(210, 180, 140),
+    "TEAL": Color(0, 128, 128),
+    "THISTLE": Color(216, 191, 216),
+    "TOMATO": Color(255, 99, 71),
+    "TURQUOISE": Color(64, 224, 208),
+    "VIOLET": Color(238, 130, 238),
+    "WHEAT": Color(245, 222, 179),
+    "WHITE": Color(255, 255, 255),
+    "WHITESMOKE": Color(245, 245, 245),
+    "YELLOW": Color(255, 255, 0),
+    "YELLOWGREEN": Color(154, 205, 50)
+}

+ 322 - 0
selenium-3.141.0/build/lib/selenium/webdriver/support/event_firing_webdriver.py

@@ -0,0 +1,322 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.common.exceptions import WebDriverException
+from selenium.webdriver.common.by import By
+from selenium.webdriver.remote.webdriver import WebDriver
+from selenium.webdriver.remote.webelement import WebElement
+from .abstract_event_listener import AbstractEventListener
+
+
+def _wrap_elements(result, ef_driver):
+    if isinstance(result, WebElement):
+        return EventFiringWebElement(result, ef_driver)
+    elif isinstance(result, list):
+        return [_wrap_elements(item, ef_driver) for item in result]
+    else:
+        return result
+
+
+class EventFiringWebDriver(object):
+    """
+    A wrapper around an arbitrary WebDriver instance which supports firing events
+    """
+
+    def __init__(self, driver, event_listener):
+        """
+        Creates a new instance of the EventFiringWebDriver
+
+        :Args:
+         - driver : A WebDriver instance
+         - event_listener : Instance of a class that subclasses AbstractEventListener and implements it fully or partially
+
+        Example:
+
+        .. code-block:: python
+
+            from selenium.webdriver import Firefox
+            from selenium.webdriver.support.events import EventFiringWebDriver, AbstractEventListener
+
+            class MyListener(AbstractEventListener):
+                def before_navigate_to(self, url, driver):
+                    print("Before navigate to %s" % url)
+                def after_navigate_to(self, url, driver):
+                    print("After navigate to %s" % url)
+
+            driver = Firefox()
+            ef_driver = EventFiringWebDriver(driver, MyListener())
+            ef_driver.get("http://www.google.co.in/")
+        """
+        if not isinstance(driver, WebDriver):
+            raise WebDriverException("A WebDriver instance must be supplied")
+        if not isinstance(event_listener, AbstractEventListener):
+            raise WebDriverException("Event listener must be a subclass of AbstractEventListener")
+        self._driver = driver
+        self._driver._wrap_value = self._wrap_value
+        self._listener = event_listener
+
+    @property
+    def wrapped_driver(self):
+        """Returns the WebDriver instance wrapped by this EventsFiringWebDriver"""
+        return self._driver
+
+    def get(self, url):
+        self._dispatch("navigate_to", (url, self._driver), "get", (url, ))
+
+    def back(self):
+        self._dispatch("navigate_back", (self._driver,), "back", ())
+
+    def forward(self):
+        self._dispatch("navigate_forward", (self._driver,), "forward", ())
+
+    def execute_script(self, script, *args):
+        unwrapped_args = (script,) + self._unwrap_element_args(args)
+        return self._dispatch("execute_script", (script, self._driver), "execute_script", unwrapped_args)
+
+    def execute_async_script(self, script, *args):
+        unwrapped_args = (script,) + self._unwrap_element_args(args)
+        return self._dispatch("execute_script", (script, self._driver), "execute_async_script", unwrapped_args)
+
+    def close(self):
+        self._dispatch("close", (self._driver,), "close", ())
+
+    def quit(self):
+        self._dispatch("quit", (self._driver,), "quit", ())
+
+    def find_element(self, by=By.ID, value=None):
+        return self._dispatch("find", (by, value, self._driver), "find_element", (by, value))
+
+    def find_elements(self, by=By.ID, value=None):
+        return self._dispatch("find", (by, value, self._driver), "find_elements", (by, value))
+
+    def find_element_by_id(self, id_):
+        return self.find_element(by=By.ID, value=id_)
+
+    def find_elements_by_id(self, id_):
+        return self.find_elements(by=By.ID, value=id_)
+
+    def find_element_by_xpath(self, xpath):
+        return self.find_element(by=By.XPATH, value=xpath)
+
+    def find_elements_by_xpath(self, xpath):
+        return self.find_elements(by=By.XPATH, value=xpath)
+
+    def find_element_by_link_text(self, link_text):
+        return self.find_element(by=By.LINK_TEXT, value=link_text)
+
+    def find_elements_by_link_text(self, text):
+        return self.find_elements(by=By.LINK_TEXT, value=text)
+
+    def find_element_by_partial_link_text(self, link_text):
+        return self.find_element(by=By.PARTIAL_LINK_TEXT, value=link_text)
+
+    def find_elements_by_partial_link_text(self, link_text):
+        return self.find_elements(by=By.PARTIAL_LINK_TEXT, value=link_text)
+
+    def find_element_by_name(self, name):
+        return self.find_element(by=By.NAME, value=name)
+
+    def find_elements_by_name(self, name):
+        return self.find_elements(by=By.NAME, value=name)
+
+    def find_element_by_tag_name(self, name):
+        return self.find_element(by=By.TAG_NAME, value=name)
+
+    def find_elements_by_tag_name(self, name):
+        return self.find_elements(by=By.TAG_NAME, value=name)
+
+    def find_element_by_class_name(self, name):
+        return self.find_element(by=By.CLASS_NAME, value=name)
+
+    def find_elements_by_class_name(self, name):
+        return self.find_elements(by=By.CLASS_NAME, value=name)
+
+    def find_element_by_css_selector(self, css_selector):
+        return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
+
+    def find_elements_by_css_selector(self, css_selector):
+        return self.find_elements(by=By.CSS_SELECTOR, value=css_selector)
+
+    def _dispatch(self, l_call, l_args, d_call, d_args):
+        getattr(self._listener, "before_%s" % l_call)(*l_args)
+        try:
+            result = getattr(self._driver, d_call)(*d_args)
+        except Exception as e:
+            self._listener.on_exception(e, self._driver)
+            raise e
+        getattr(self._listener, "after_%s" % l_call)(*l_args)
+        return _wrap_elements(result, self)
+
+    def _unwrap_element_args(self, args):
+        if isinstance(args, EventFiringWebElement):
+            return args.wrapped_element
+        elif isinstance(args, tuple):
+            return tuple([self._unwrap_element_args(item) for item in args])
+        elif isinstance(args, list):
+            return [self._unwrap_element_args(item) for item in args]
+        else:
+            return args
+
+    def _wrap_value(self, value):
+        if isinstance(value, EventFiringWebElement):
+            return WebDriver._wrap_value(self._driver, value.wrapped_element)
+        return WebDriver._wrap_value(self._driver, value)
+
+    def __setattr__(self, item, value):
+        if item.startswith("_") or not hasattr(self._driver, item):
+            object.__setattr__(self, item, value)
+        else:
+            try:
+                object.__setattr__(self._driver, item, value)
+            except Exception as e:
+                self._listener.on_exception(e, self._driver)
+                raise e
+
+    def __getattr__(self, name):
+        def _wrap(*args, **kwargs):
+            try:
+                result = attrib(*args, **kwargs)
+                return _wrap_elements(result, self)
+            except Exception as e:
+                self._listener.on_exception(e, self._driver)
+                raise
+
+        try:
+            attrib = getattr(self._driver, name)
+            return _wrap if callable(attrib) else attrib
+        except Exception as e:
+            self._listener.on_exception(e, self._driver)
+            raise
+
+
+class EventFiringWebElement(object):
+    """"
+    A wrapper around WebElement instance which supports firing events
+    """
+
+    def __init__(self, webelement, ef_driver):
+        """
+        Creates a new instance of the EventFiringWebElement
+        """
+        self._webelement = webelement
+        self._ef_driver = ef_driver
+        self._driver = ef_driver.wrapped_driver
+        self._listener = ef_driver._listener
+
+    @property
+    def wrapped_element(self):
+        """Returns the WebElement wrapped by this EventFiringWebElement instance"""
+        return self._webelement
+
+    def click(self):
+        self._dispatch("click", (self._webelement, self._driver), "click", ())
+
+    def clear(self):
+        self._dispatch("change_value_of", (self._webelement, self._driver), "clear", ())
+
+    def send_keys(self, *value):
+        self._dispatch("change_value_of", (self._webelement, self._driver), "send_keys", value)
+
+    def find_element(self, by=By.ID, value=None):
+        return self._dispatch("find", (by, value, self._driver), "find_element", (by, value))
+
+    def find_elements(self, by=By.ID, value=None):
+        return self._dispatch("find", (by, value, self._driver), "find_elements", (by, value))
+
+    def find_element_by_id(self, id_):
+        return self.find_element(by=By.ID, value=id_)
+
+    def find_elements_by_id(self, id_):
+        return self.find_elements(by=By.ID, value=id_)
+
+    def find_element_by_name(self, name):
+        return self.find_element(by=By.NAME, value=name)
+
+    def find_elements_by_name(self, name):
+        return self.find_elements(by=By.NAME, value=name)
+
+    def find_element_by_link_text(self, link_text):
+        return self.find_element(by=By.LINK_TEXT, value=link_text)
+
+    def find_elements_by_link_text(self, link_text):
+        return self.find_elements(by=By.LINK_TEXT, value=link_text)
+
+    def find_element_by_partial_link_text(self, link_text):
+        return self.find_element(by=By.PARTIAL_LINK_TEXT, value=link_text)
+
+    def find_elements_by_partial_link_text(self, link_text):
+        return self.find_elements(by=By.PARTIAL_LINK_TEXT, value=link_text)
+
+    def find_element_by_tag_name(self, name):
+        return self.find_element(by=By.TAG_NAME, value=name)
+
+    def find_elements_by_tag_name(self, name):
+        return self.find_elements(by=By.TAG_NAME, value=name)
+
+    def find_element_by_xpath(self, xpath):
+        return self.find_element(by=By.XPATH, value=xpath)
+
+    def find_elements_by_xpath(self, xpath):
+        return self.find_elements(by=By.XPATH, value=xpath)
+
+    def find_element_by_class_name(self, name):
+        return self.find_element(by=By.CLASS_NAME, value=name)
+
+    def find_elements_by_class_name(self, name):
+        return self.find_elements(by=By.CLASS_NAME, value=name)
+
+    def find_element_by_css_selector(self, css_selector):
+        return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
+
+    def find_elements_by_css_selector(self, css_selector):
+        return self.find_elements(by=By.CSS_SELECTOR, value=css_selector)
+
+    def _dispatch(self, l_call, l_args, d_call, d_args):
+        getattr(self._listener, "before_%s" % l_call)(*l_args)
+        try:
+            result = getattr(self._webelement, d_call)(*d_args)
+        except Exception as e:
+            self._listener.on_exception(e, self._driver)
+            raise e
+        getattr(self._listener, "after_%s" % l_call)(*l_args)
+        return _wrap_elements(result, self._ef_driver)
+
+    def __setattr__(self, item, value):
+        if item.startswith("_") or not hasattr(self._webelement, item):
+            object.__setattr__(self, item, value)
+        else:
+            try:
+                object.__setattr__(self._webelement, item, value)
+            except Exception as e:
+                self._listener.on_exception(e, self._driver)
+                raise e
+
+    def __getattr__(self, name):
+        def _wrap(*args, **kwargs):
+            try:
+                result = attrib(*args, **kwargs)
+                return _wrap_elements(result, self._ef_driver)
+            except Exception as e:
+                self._listener.on_exception(e, self._driver)
+                raise
+
+        try:
+            attrib = getattr(self._webelement, name)
+            return _wrap if callable(attrib) else attrib
+        except Exception as e:
+            self._listener.on_exception(e, self._driver)
+            raise

+ 19 - 0
selenium-3.141.0/build/lib/selenium/webdriver/support/events.py

@@ -0,0 +1,19 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from .abstract_event_listener import AbstractEventListener  # noqa
+from .event_firing_webdriver import EventFiringWebDriver  # noqa

+ 422 - 0
selenium-3.141.0/build/lib/selenium/webdriver/support/expected_conditions.py

@@ -0,0 +1,422 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.common.exceptions import NoSuchElementException
+from selenium.common.exceptions import NoSuchFrameException
+from selenium.common.exceptions import StaleElementReferenceException
+from selenium.common.exceptions import WebDriverException
+from selenium.common.exceptions import NoAlertPresentException
+from selenium.webdriver.remote.webdriver import WebElement
+
+"""
+ * Canned "Expected Conditions" which are generally useful within webdriver
+ * tests.
+"""
+
+
+class title_is(object):
+    """An expectation for checking the title of a page.
+    title is the expected title, which must be an exact match
+    returns True if the title matches, false otherwise."""
+    def __init__(self, title):
+        self.title = title
+
+    def __call__(self, driver):
+        return self.title == driver.title
+
+
+class title_contains(object):
+    """ An expectation for checking that the title contains a case-sensitive
+    substring. title is the fragment of title expected
+    returns True when the title matches, False otherwise
+    """
+    def __init__(self, title):
+        self.title = title
+
+    def __call__(self, driver):
+        return self.title in driver.title
+
+
+class presence_of_element_located(object):
+    """ An expectation for checking that an element is present on the DOM
+    of a page. This does not necessarily mean that the element is visible.
+    locator - used to find the element
+    returns the WebElement once it is located
+    """
+    def __init__(self, locator):
+        self.locator = locator
+
+    def __call__(self, driver):
+        return _find_element(driver, self.locator)
+
+
+class url_contains(object):
+    """ An expectation for checking that the current url contains a
+    case-sensitive substring.
+    url is the fragment of url expected,
+    returns True when the url matches, False otherwise
+    """
+    def __init__(self, url):
+        self.url = url
+
+    def __call__(self, driver):
+        return self.url in driver.current_url
+
+
+class url_matches(object):
+    """An expectation for checking the current url.
+    pattern is the expected pattern, which must be an exact match
+    returns True if the url matches, false otherwise."""
+    def __init__(self, pattern):
+        self.pattern = pattern
+
+    def __call__(self, driver):
+        import re
+        match = re.search(self.pattern, driver.current_url)
+
+        return match is not None
+
+
+class url_to_be(object):
+    """An expectation for checking the current url.
+    url is the expected url, which must be an exact match
+    returns True if the url matches, false otherwise."""
+    def __init__(self, url):
+        self.url = url
+
+    def __call__(self, driver):
+        return self.url == driver.current_url
+
+
+class url_changes(object):
+    """An expectation for checking the current url.
+    url is the expected url, which must not be an exact match
+    returns True if the url is different, false otherwise."""
+    def __init__(self, url):
+        self.url = url
+
+    def __call__(self, driver):
+        return self.url != driver.current_url
+
+
+class visibility_of_element_located(object):
+    """ An expectation for checking that an element is present on the DOM of a
+    page and visible. Visibility means that the element is not only displayed
+    but also has a height and width that is greater than 0.
+    locator - used to find the element
+    returns the WebElement once it is located and visible
+    """
+    def __init__(self, locator):
+        self.locator = locator
+
+    def __call__(self, driver):
+        try:
+            return _element_if_visible(_find_element(driver, self.locator))
+        except StaleElementReferenceException:
+            return False
+
+
+class visibility_of(object):
+    """ An expectation for checking that an element, known to be present on the
+    DOM of a page, is visible. Visibility means that the element is not only
+    displayed but also has a height and width that is greater than 0.
+    element is the WebElement
+    returns the (same) WebElement once it is visible
+    """
+    def __init__(self, element):
+        self.element = element
+
+    def __call__(self, ignored):
+        return _element_if_visible(self.element)
+
+
+def _element_if_visible(element, visibility=True):
+    return element if element.is_displayed() == visibility else False
+
+
+class presence_of_all_elements_located(object):
+    """ An expectation for checking that there is at least one element present
+    on a web page.
+    locator is used to find the element
+    returns the list of WebElements once they are located
+    """
+    def __init__(self, locator):
+        self.locator = locator
+
+    def __call__(self, driver):
+        return _find_elements(driver, self.locator)
+
+
+class visibility_of_any_elements_located(object):
+    """ An expectation for checking that there is at least one element visible
+    on a web page.
+    locator is used to find the element
+    returns the list of WebElements once they are located
+    """
+    def __init__(self, locator):
+        self.locator = locator
+
+    def __call__(self, driver):
+        return [element for element in _find_elements(driver, self.locator) if _element_if_visible(element)]
+
+
+class visibility_of_all_elements_located(object):
+    """ An expectation for checking that all elements are present on the DOM of a
+    page and visible. Visibility means that the elements are not only displayed
+    but also has a height and width that is greater than 0.
+    locator - used to find the elements
+    returns the list of WebElements once they are located and visible
+    """
+    def __init__(self, locator):
+        self.locator = locator
+
+    def __call__(self, driver):
+        try:
+            elements = _find_elements(driver, self.locator)
+            for element in elements:
+                if _element_if_visible(element, visibility=False):
+                    return False
+            return elements
+        except StaleElementReferenceException:
+            return False
+
+
+class text_to_be_present_in_element(object):
+    """ An expectation for checking if the given text is present in the
+    specified element.
+    locator, text
+    """
+    def __init__(self, locator, text_):
+        self.locator = locator
+        self.text = text_
+
+    def __call__(self, driver):
+        try:
+            element_text = _find_element(driver, self.locator).text
+            return self.text in element_text
+        except StaleElementReferenceException:
+            return False
+
+
+class text_to_be_present_in_element_value(object):
+    """
+    An expectation for checking if the given text is present in the element's
+    locator, text
+    """
+    def __init__(self, locator, text_):
+        self.locator = locator
+        self.text = text_
+
+    def __call__(self, driver):
+        try:
+            element_text = _find_element(driver,
+                                         self.locator).get_attribute("value")
+            if element_text:
+                return self.text in element_text
+            else:
+                return False
+        except StaleElementReferenceException:
+                return False
+
+
+class frame_to_be_available_and_switch_to_it(object):
+    """ An expectation for checking whether the given frame is available to
+    switch to.  If the frame is available it switches the given driver to the
+    specified frame.
+    """
+    def __init__(self, locator):
+        self.frame_locator = locator
+
+    def __call__(self, driver):
+        try:
+            if isinstance(self.frame_locator, tuple):
+                driver.switch_to.frame(_find_element(driver,
+                                                     self.frame_locator))
+            else:
+                driver.switch_to.frame(self.frame_locator)
+            return True
+        except NoSuchFrameException:
+            return False
+
+
+class invisibility_of_element_located(object):
+    """ An Expectation for checking that an element is either invisible or not
+    present on the DOM.
+
+    locator used to find the element
+    """
+    def __init__(self, locator):
+        self.target = locator
+
+    def __call__(self, driver):
+        try:
+            target = self.target
+            if not isinstance(target, WebElement):
+                target = _find_element(driver, target)
+            return _element_if_visible(target, False)
+        except (NoSuchElementException, StaleElementReferenceException):
+            # In the case of NoSuchElement, returns true because the element is
+            # not present in DOM. The try block checks if the element is present
+            # but is invisible.
+            # In the case of StaleElementReference, returns true because stale
+            # element reference implies that element is no longer visible.
+            return True
+
+
+class invisibility_of_element(invisibility_of_element_located):
+    """ An Expectation for checking that an element is either invisible or not
+    present on the DOM.
+
+    element is either a locator (text) or an WebElement
+    """
+    def __init(self, element):
+        self.target = element
+
+
+class element_to_be_clickable(object):
+    """ An Expectation for checking an element is visible and enabled such that
+    you can click it."""
+    def __init__(self, locator):
+        self.locator = locator
+
+    def __call__(self, driver):
+        element = visibility_of_element_located(self.locator)(driver)
+        if element and element.is_enabled():
+            return element
+        else:
+            return False
+
+
+class staleness_of(object):
+    """ Wait until an element is no longer attached to the DOM.
+    element is the element to wait for.
+    returns False if the element is still attached to the DOM, true otherwise.
+    """
+    def __init__(self, element):
+        self.element = element
+
+    def __call__(self, ignored):
+        try:
+            # Calling any method forces a staleness check
+            self.element.is_enabled()
+            return False
+        except StaleElementReferenceException:
+            return True
+
+
+class element_to_be_selected(object):
+    """ An expectation for checking the selection is selected.
+    element is WebElement object
+    """
+    def __init__(self, element):
+        self.element = element
+
+    def __call__(self, ignored):
+        return self.element.is_selected()
+
+
+class element_located_to_be_selected(object):
+    """An expectation for the element to be located is selected.
+    locator is a tuple of (by, path)"""
+    def __init__(self, locator):
+        self.locator = locator
+
+    def __call__(self, driver):
+        return _find_element(driver, self.locator).is_selected()
+
+
+class element_selection_state_to_be(object):
+    """ An expectation for checking if the given element is selected.
+    element is WebElement object
+    is_selected is a Boolean."
+    """
+    def __init__(self, element, is_selected):
+        self.element = element
+        self.is_selected = is_selected
+
+    def __call__(self, ignored):
+        return self.element.is_selected() == self.is_selected
+
+
+class element_located_selection_state_to_be(object):
+    """ An expectation to locate an element and check if the selection state
+    specified is in that state.
+    locator is a tuple of (by, path)
+    is_selected is a boolean
+    """
+    def __init__(self, locator, is_selected):
+        self.locator = locator
+        self.is_selected = is_selected
+
+    def __call__(self, driver):
+        try:
+            element = _find_element(driver, self.locator)
+            return element.is_selected() == self.is_selected
+        except StaleElementReferenceException:
+            return False
+
+
+class number_of_windows_to_be(object):
+    """ An expectation for the number of windows to be a certain value."""
+
+    def __init__(self, num_windows):
+        self.num_windows = num_windows
+
+    def __call__(self, driver):
+        return len(driver.window_handles) == self.num_windows
+
+
+class new_window_is_opened(object):
+    """ An expectation that a new window will be opened and have the number of
+    windows handles increase"""
+
+    def __init__(self, current_handles):
+        self.current_handles = current_handles
+
+    def __call__(self, driver):
+        return len(driver.window_handles) > len(self.current_handles)
+
+
+class alert_is_present(object):
+    """ Expect an alert to be present."""
+    def __init__(self):
+        pass
+
+    def __call__(self, driver):
+        try:
+            alert = driver.switch_to.alert
+            return alert
+        except NoAlertPresentException:
+            return False
+
+
+def _find_element(driver, by):
+    """Looks up an element. Logs and re-raises ``WebDriverException``
+    if thrown."""
+    try:
+        return driver.find_element(*by)
+    except NoSuchElementException as e:
+        raise e
+    except WebDriverException as e:
+        raise e
+
+
+def _find_elements(driver, by):
+    try:
+        return driver.find_elements(*by)
+    except WebDriverException as e:
+        raise e

+ 241 - 0
selenium-3.141.0/build/lib/selenium/webdriver/support/select.py

@@ -0,0 +1,241 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from selenium.webdriver.common.by import By
+from selenium.common.exceptions import NoSuchElementException, UnexpectedTagNameException
+
+
+class Select(object):
+
+    def __init__(self, webelement):
+        """
+        Constructor. A check is made that the given element is, indeed, a SELECT tag. If it is not,
+        then an UnexpectedTagNameException is thrown.
+
+        :Args:
+         - webelement - element SELECT element to wrap
+
+        Example:
+            from selenium.webdriver.support.ui import Select \n
+            Select(driver.find_element_by_tag_name("select")).select_by_index(2)
+        """
+        if webelement.tag_name.lower() != "select":
+            raise UnexpectedTagNameException(
+                "Select only works on <select> elements, not on <%s>" %
+                webelement.tag_name)
+        self._el = webelement
+        multi = self._el.get_attribute("multiple")
+        self.is_multiple = multi and multi != "false"
+
+    @property
+    def options(self):
+        """Returns a list of all options belonging to this select tag"""
+        return self._el.find_elements(By.TAG_NAME, 'option')
+
+    @property
+    def all_selected_options(self):
+        """Returns a list of all selected options belonging to this select tag"""
+        ret = []
+        for opt in self.options:
+            if opt.is_selected():
+                ret.append(opt)
+        return ret
+
+    @property
+    def first_selected_option(self):
+        """The first selected option in this select tag (or the currently selected option in a
+        normal select)"""
+        for opt in self.options:
+            if opt.is_selected():
+                return opt
+        raise NoSuchElementException("No options are selected")
+
+    def select_by_value(self, value):
+        """Select all options that have a value matching the argument. That is, when given "foo" this
+           would select an option like:
+
+           <option value="foo">Bar</option>
+
+           :Args:
+            - value - The value to match against
+
+           throws NoSuchElementException If there is no option with specisied value in SELECT
+           """
+        css = "option[value =%s]" % self._escapeString(value)
+        opts = self._el.find_elements(By.CSS_SELECTOR, css)
+        matched = False
+        for opt in opts:
+            self._setSelected(opt)
+            if not self.is_multiple:
+                return
+            matched = True
+        if not matched:
+            raise NoSuchElementException("Cannot locate option with value: %s" % value)
+
+    def select_by_index(self, index):
+        """Select the option at the given index. This is done by examing the "index" attribute of an
+           element, and not merely by counting.
+
+           :Args:
+            - index - The option at this index will be selected
+
+           throws NoSuchElementException If there is no option with specisied index in SELECT
+           """
+        match = str(index)
+        for opt in self.options:
+            if opt.get_attribute("index") == match:
+                self._setSelected(opt)
+                return
+        raise NoSuchElementException("Could not locate element with index %d" % index)
+
+    def select_by_visible_text(self, text):
+        """Select all options that display text matching the argument. That is, when given "Bar" this
+           would select an option like:
+
+            <option value="foo">Bar</option>
+
+           :Args:
+            - text - The visible text to match against
+
+            throws NoSuchElementException If there is no option with specisied text in SELECT
+           """
+        xpath = ".//option[normalize-space(.) = %s]" % self._escapeString(text)
+        opts = self._el.find_elements(By.XPATH, xpath)
+        matched = False
+        for opt in opts:
+            self._setSelected(opt)
+            if not self.is_multiple:
+                return
+            matched = True
+
+        if len(opts) == 0 and " " in text:
+            subStringWithoutSpace = self._get_longest_token(text)
+            if subStringWithoutSpace == "":
+                candidates = self.options
+            else:
+                xpath = ".//option[contains(.,%s)]" % self._escapeString(subStringWithoutSpace)
+                candidates = self._el.find_elements(By.XPATH, xpath)
+            for candidate in candidates:
+                if text == candidate.text:
+                    self._setSelected(candidate)
+                    if not self.is_multiple:
+                        return
+                    matched = True
+
+        if not matched:
+            raise NoSuchElementException("Could not locate element with visible text: %s" % text)
+
+    def deselect_all(self):
+        """Clear all selected entries. This is only valid when the SELECT supports multiple selections.
+           throws NotImplementedError If the SELECT does not support multiple selections
+        """
+        if not self.is_multiple:
+            raise NotImplementedError("You may only deselect all options of a multi-select")
+        for opt in self.options:
+            self._unsetSelected(opt)
+
+    def deselect_by_value(self, value):
+        """Deselect all options that have a value matching the argument. That is, when given "foo" this
+           would deselect an option like:
+
+            <option value="foo">Bar</option>
+
+           :Args:
+            - value - The value to match against
+
+            throws NoSuchElementException If there is no option with specisied value in SELECT
+        """
+        if not self.is_multiple:
+            raise NotImplementedError("You may only deselect options of a multi-select")
+        matched = False
+        css = "option[value = %s]" % self._escapeString(value)
+        opts = self._el.find_elements(By.CSS_SELECTOR, css)
+        for opt in opts:
+            self._unsetSelected(opt)
+            matched = True
+        if not matched:
+            raise NoSuchElementException("Could not locate element with value: %s" % value)
+
+    def deselect_by_index(self, index):
+        """Deselect the option at the given index. This is done by examing the "index" attribute of an
+           element, and not merely by counting.
+
+           :Args:
+            - index - The option at this index will be deselected
+
+            throws NoSuchElementException If there is no option with specisied index in SELECT
+        """
+        if not self.is_multiple:
+            raise NotImplementedError("You may only deselect options of a multi-select")
+        for opt in self.options:
+            if opt.get_attribute("index") == str(index):
+                self._unsetSelected(opt)
+                return
+        raise NoSuchElementException("Could not locate element with index %d" % index)
+
+    def deselect_by_visible_text(self, text):
+        """Deselect all options that display text matching the argument. That is, when given "Bar" this
+           would deselect an option like:
+
+           <option value="foo">Bar</option>
+
+           :Args:
+            - text - The visible text to match against
+        """
+        if not self.is_multiple:
+            raise NotImplementedError("You may only deselect options of a multi-select")
+        matched = False
+        xpath = ".//option[normalize-space(.) = %s]" % self._escapeString(text)
+        opts = self._el.find_elements(By.XPATH, xpath)
+        for opt in opts:
+            self._unsetSelected(opt)
+            matched = True
+        if not matched:
+            raise NoSuchElementException("Could not locate element with visible text: %s" % text)
+
+    def _setSelected(self, option):
+        if not option.is_selected():
+            option.click()
+
+    def _unsetSelected(self, option):
+        if option.is_selected():
+            option.click()
+
+    def _escapeString(self, value):
+        if '"' in value and "'" in value:
+            substrings = value.split("\"")
+            result = ["concat("]
+            for substring in substrings:
+                result.append("\"%s\"" % substring)
+                result.append(", '\"', ")
+            result = result[0:-1]
+            if value.endswith('"'):
+                result.append(", '\"'")
+            return "".join(result) + ")"
+
+        if '"' in value:
+            return "'%s'" % value
+
+        return "\"%s\"" % value
+
+    def _get_longest_token(self, value):
+        items = value.split(" ")
+        longest = ""
+        for item in items:
+            if len(item) > len(longest):
+                longest = item
+        return longest

+ 19 - 0
selenium-3.141.0/build/lib/selenium/webdriver/support/ui.py

@@ -0,0 +1,19 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from .select import Select  # noqa
+from .wait import WebDriverWait  # noqa

+ 0 - 0
selenium-3.141.0/build/lib/selenium/webdriver/support/wait.py


部分文件因为文件数量过多而无法显示