prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Use Binder Build API for Builds in PRs
  # Description
  
  After a discussion with @minrk and @betatim on the jupyterhub/binder Gitter, it was made clear that the use of Selenium in [`binder/trigger_binder.py`](https://github.com/diana-hep/pyhf/blob/c81f6007309f4c13241f9efac187594337d0bd08/binder/trigger_binder.py) (and the script itself) is unnecessary. Instead a simple API call can be made just using Python's `webbrowser` with an [endpoint of the form `https://mybinder.org/build/gh/owner/repo/ref`](https://gitter.im/jupyterhub/binder?at=5c2f87038dafa715c73ff54f) as can be [seen in the Binder Hub demo](https://github.com/jupyterhub/binderhub/blob/9ca8fa68bb8b69c6a2736f2275279583073f314f/examples/binder-api.py#L28) (thanks Tim for the link).
  
  So, for example
  
  ```
  python -m webbrowser "https://mybinder.org/build/gh/diana-hep/pyhf/master"
  ```
  
  So asking [WWKHTD](https://github.com/kelseyhightower/nocode), this means that `binder/trigger_binder.py` is unnecessary and should be removed and `.travis.yml` should be updated to use the API calls.
  
  </issue>
  <code>
  [start of binder/trigger_binder.py]
  1 #!/usr/bin/env python
  2 
  3 import argparse
  4 from contextlib import contextmanager
  5 from selenium import webdriver
  6 from selenium.webdriver.chrome.options import Options
  7 from selenium.webdriver.support.ui import WebDriverWait
  8 from selenium.webdriver.support.expected_conditions import staleness_of
  9 
  10 
  11 class SeleniumSession:
  12     def __init__(self, args):
  13         self.options = Options()
  14         self.options.set_headless()
  15         self.options.add_argument('--no-sandbox')
  16         if args.chromedriver_path is not None:
  17             self.browser = webdriver.Chrome(
  18                 args.chromedriver_path, chrome_options=self.options
  19             )
  20         else:
  21             self.browser = webdriver.Chrome(chrome_options=self.options)
  22 
  23     @contextmanager
  24     def wait_for_page_load(self, timeout=20):
  25         old_page = self.browser.find_element_by_tag_name('html')
  26         yield
  27         WebDriverWait(self.browser, timeout).until(staleness_of(old_page))
  28 
  29     def trigger_binder(self, url):
  30         with self.wait_for_page_load():
  31             self.browser.get(url)
  32 
  33 
  34 def main(args):
  35     driver = SeleniumSession(args)
  36     if args.is_verbose:
  37         print('Chrome Headless Browser Invoked')
  38     driver.trigger_binder(args.url)
  39 
  40 
  41 if __name__ == '__main__':
  42     parser = argparse.ArgumentParser()
  43     parser.add_argument(
  44         '-v',
  45         '--verbose',
  46         dest='is_verbose',
  47         action='store_true',
  48         help='Print out more information',
  49     )
  50     parser.add_argument(
  51         '--chromedriver-path',
  52         dest='chromedriver_path',
  53         type=str,
  54         default=None,
  55         help='System path to ChromeDriver',
  56     )
  57     parser.add_argument(
  58         '--url', dest='url', type=str, default=None, help='URL for Selinium to open'
  59     )
  60     args = parser.parse_args()
  61 
  62     main(args)
  63
  [end of binder/trigger_binder.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/binder/trigger_binder.py b/binder/trigger_binder.py
  deleted file mode 100644
  --- a/binder/trigger_binder.py
  +++ /dev/null
  @@ -1,62 +0,0 @@
  -#!/usr/bin/env python
  -
  -import argparse
  -from contextlib import contextmanager
  -from selenium import webdriver
  -from selenium.webdriver.chrome.options import Options
  -from selenium.webdriver.support.ui import WebDriverWait
  -from selenium.webdriver.support.expected_conditions import staleness_of
  -
  -
  -class SeleniumSession:
  -    def __init__(self, args):
  -        self.options = Options()
  -        self.options.set_headless()
  -        self.options.add_argument('--no-sandbox')
  -        if args.chromedriver_path is not None:
  -            self.browser = webdriver.Chrome(
  -                args.chromedriver_path, chrome_options=self.options
  -            )
  -        else:
  -            self.browser = webdriver.Chrome(chrome_options=self.options)
  -
  -    @contextmanager
  -    def wait_for_page_load(self, timeout=20):
  -        old_page = self.browser.find_element_by_tag_name('html')
  -        yield
  -        WebDriverWait(self.browser, timeout).until(staleness_of(old_page))
  -
  -    def trigger_binder(self, url):
  -        with self.wait_for_page_load():
  -            self.browser.get(url)
  -
  -
  -def main(args):
  -    driver = SeleniumSession(args)
  -    if args.is_verbose:
  -        print('Chrome Headless Browser Invoked')
  -    driver.trigger_binder(args.url)
  -
  -
  -if __name__ == '__main__':
  -    parser = argparse.ArgumentParser()
  -    parser.add_argument(
  -        '-v',
  -        '--verbose',
  -        dest='is_verbose',
  -        action='store_true',
  -        help='Print out more information',
  -    )
  -    parser.add_argument(
  -        '--chromedriver-path',
  -        dest='chromedriver_path',
  -        type=str,
  -        default=None,
  -        help='System path to ChromeDriver',
  -    )
  -    parser.add_argument(
  -        '--url', dest='url', type=str, default=None, help='URL for Selinium to open'
  -    )
  -    args = parser.parse_args()
  -
  -    main(args)
  
verification_info: {"golden_diff": "diff --git a/binder/trigger_binder.py b/binder/trigger_binder.py\ndeleted file mode 100644\n--- a/binder/trigger_binder.py\n+++ /dev/null\n@@ -1,62 +0,0 @@\n-#!/usr/bin/env python\n-\n-import argparse\n-from contextlib import contextmanager\n-from selenium import webdriver\n-from selenium.webdriver.chrome.options import Options\n-from selenium.webdriver.support.ui import WebDriverWait\n-from selenium.webdriver.support.expected_conditions import staleness_of\n-\n-\n-class SeleniumSession:\n-    def __init__(self, args):\n-        self.options = Options()\n-        self.options.set_headless()\n-        self.options.add_argument('--no-sandbox')\n-        if args.chromedriver_path is not None:\n-            self.browser = webdriver.Chrome(\n-                args.chromedriver_path, chrome_options=self.options\n-            )\n-        else:\n-            self.browser = webdriver.Chrome(chrome_options=self.options)\n-\n-    @contextmanager\n-    def wait_for_page_load(self, timeout=20):\n-        old_page = self.browser.find_element_by_tag_name('html')\n-        yield\n-        WebDriverWait(self.browser, timeout).until(staleness_of(old_page))\n-\n-    def trigger_binder(self, url):\n-        with self.wait_for_page_load():\n-            self.browser.get(url)\n-\n-\n-def main(args):\n-    driver = SeleniumSession(args)\n-    if args.is_verbose:\n-        print('Chrome Headless Browser Invoked')\n-    driver.trigger_binder(args.url)\n-\n-\n-if __name__ == '__main__':\n-    parser = argparse.ArgumentParser()\n-    parser.add_argument(\n-        '-v',\n-        '--verbose',\n-        dest='is_verbose',\n-        action='store_true',\n-        help='Print out more information',\n-    )\n-    parser.add_argument(\n-        '--chromedriver-path',\n-        dest='chromedriver_path',\n-        type=str,\n-        default=None,\n-        help='System path to ChromeDriver',\n-    )\n-    parser.add_argument(\n-        '--url', dest='url', type=str, default=None, help='URL for Selinium to open'\n-    )\n-    args = parser.parse_args()\n-\n-    main(args)\n", "issue": "Use Binder Build API for Builds in PRs\n# Description\r\n\r\nAfter a discussion with @minrk and @betatim on the jupyterhub/binder Gitter, it was made clear that the use of Selenium in [`binder/trigger_binder.py`](https://github.com/diana-hep/pyhf/blob/c81f6007309f4c13241f9efac187594337d0bd08/binder/trigger_binder.py) (and the script itself) is unnecessary. Instead a simple API call can be made just using Python's `webbrowser` with an [endpoint of the form `https://mybinder.org/build/gh/owner/repo/ref`](https://gitter.im/jupyterhub/binder?at=5c2f87038dafa715c73ff54f) as can be [seen in the Binder Hub demo](https://github.com/jupyterhub/binderhub/blob/9ca8fa68bb8b69c6a2736f2275279583073f314f/examples/binder-api.py#L28) (thanks Tim for the link).\r\n\r\nSo, for example\r\n\r\n```\r\npython -m webbrowser \"https://mybinder.org/build/gh/diana-hep/pyhf/master\"\r\n```\r\n\r\nSo asking [WWKHTD](https://github.com/kelseyhightower/nocode), this means that `binder/trigger_binder.py` is unnecessary and should be removed and `.travis.yml` should be updated to use the API calls.\n", "before_files": [{"content": "#!/usr/bin/env python\n\nimport argparse\nfrom contextlib import contextmanager\nfrom selenium import webdriver\nfrom selenium.webdriver.chrome.options import Options\nfrom selenium.webdriver.support.ui import WebDriverWait\nfrom selenium.webdriver.support.expected_conditions import staleness_of\n\n\nclass SeleniumSession:\n    def __init__(self, args):\n        self.options = Options()\n        self.options.set_headless()\n        self.options.add_argument('--no-sandbox')\n        if args.chromedriver_path is not None:\n            self.browser = webdriver.Chrome(\n                args.chromedriver_path, chrome_options=self.options\n            )\n        else:\n            self.browser = webdriver.Chrome(chrome_options=self.options)\n\n    @contextmanager\n    def wait_for_page_load(self, timeout=20):\n        old_page = self.browser.find_element_by_tag_name('html')\n        yield\n        WebDriverWait(self.browser, timeout).until(staleness_of(old_page))\n\n    def trigger_binder(self, url):\n        with self.wait_for_page_load():\n            self.browser.get(url)\n\n\ndef main(args):\n    driver = SeleniumSession(args)\n    if args.is_verbose:\n        print('Chrome Headless Browser Invoked')\n    driver.trigger_binder(args.url)\n\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\n        '-v',\n        '--verbose',\n        dest='is_verbose',\n        action='store_true',\n        help='Print out more information',\n    )\n    parser.add_argument(\n        '--chromedriver-path',\n        dest='chromedriver_path',\n        type=str,\n        default=None,\n        help='System path to ChromeDriver',\n    )\n    parser.add_argument(\n        '--url', dest='url', type=str, default=None, help='URL for Selinium to open'\n    )\n    args = parser.parse_args()\n\n    main(args)\n", "path": "binder/trigger_binder.py"}]}