poltergeistFork 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +425 -0
  4. data/lib/capybara/poltergeist/browser.rb +426 -0
  5. data/lib/capybara/poltergeist/client.rb +151 -0
  6. data/lib/capybara/poltergeist/client/agent.coffee +423 -0
  7. data/lib/capybara/poltergeist/client/browser.coffee +497 -0
  8. data/lib/capybara/poltergeist/client/cmd.coffee +17 -0
  9. data/lib/capybara/poltergeist/client/compiled/agent.js +587 -0
  10. data/lib/capybara/poltergeist/client/compiled/browser.js +687 -0
  11. data/lib/capybara/poltergeist/client/compiled/cmd.js +31 -0
  12. data/lib/capybara/poltergeist/client/compiled/connection.js +25 -0
  13. data/lib/capybara/poltergeist/client/compiled/main.js +228 -0
  14. data/lib/capybara/poltergeist/client/compiled/node.js +88 -0
  15. data/lib/capybara/poltergeist/client/compiled/web_page.js +539 -0
  16. data/lib/capybara/poltergeist/client/connection.coffee +11 -0
  17. data/lib/capybara/poltergeist/client/main.coffee +99 -0
  18. data/lib/capybara/poltergeist/client/node.coffee +70 -0
  19. data/lib/capybara/poltergeist/client/pre/agent.js +587 -0
  20. data/lib/capybara/poltergeist/client/pre/browser.js +688 -0
  21. data/lib/capybara/poltergeist/client/pre/cmd.js +31 -0
  22. data/lib/capybara/poltergeist/client/pre/connection.js +25 -0
  23. data/lib/capybara/poltergeist/client/pre/main.js +228 -0
  24. data/lib/capybara/poltergeist/client/pre/node.js +88 -0
  25. data/lib/capybara/poltergeist/client/pre/web_page.js +540 -0
  26. data/lib/capybara/poltergeist/client/web_page.coffee +372 -0
  27. data/lib/capybara/poltergeist/command.rb +17 -0
  28. data/lib/capybara/poltergeist/cookie.rb +35 -0
  29. data/lib/capybara/poltergeist/driver.rb +394 -0
  30. data/lib/capybara/poltergeist/errors.rb +183 -0
  31. data/lib/capybara/poltergeist/inspector.rb +46 -0
  32. data/lib/capybara/poltergeist/json.rb +25 -0
  33. data/lib/capybara/poltergeist/network_traffic.rb +7 -0
  34. data/lib/capybara/poltergeist/network_traffic/error.rb +19 -0
  35. data/lib/capybara/poltergeist/network_traffic/request.rb +27 -0
  36. data/lib/capybara/poltergeist/network_traffic/response.rb +40 -0
  37. data/lib/capybara/poltergeist/node.rb +177 -0
  38. data/lib/capybara/poltergeist/server.rb +36 -0
  39. data/lib/capybara/poltergeist/utility.rb +9 -0
  40. data/lib/capybara/poltergeist/version.rb +5 -0
  41. data/lib/capybara/poltergeist/web_socket_server.rb +107 -0
  42. data/lib/capybara/poltergeistFork.rb +27 -0
  43. metadata +268 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c2ac06b5319e9470247b99722597ba45c2e57614
4
+ data.tar.gz: 17a8f83125d27a4e5fe0e36dba385acb8467d69a
5
+ SHA512:
6
+ metadata.gz: 5bfe28897e09f0f7fdb14499ee3f9279fd8ecb41ded470d0ecdf929d4ba5d4c630a21464748d8feecdd916bc945be922cac57fd2ea6a41b9d55f70d98e78b761
7
+ data.tar.gz: 443c3f007cfe1a5b54cd05939576c168a4d48331aca327e81d62a828778b4a52f33c35c1ff086f390de5efef1470902d29964d12337c524a427c76ee7b3decfa
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 vianull
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,425 @@
1
+ # Poltergeist - A PhantomJS driver for Capybara #
2
+
3
+ [![Build Status](https://secure.travis-ci.org/teampoltergeist/poltergeist.png)](http://travis-ci.org/teampoltergeist/poltergeist)
4
+
5
+ Poltergeist is a driver for [Capybara](https://github.com/jnicklas/capybara). It allows you to
6
+ run your Capybara tests on a headless [WebKit](http://webkit.org) browser,
7
+ provided by [PhantomJS](http://phantomjs.org/).
8
+
9
+ **If you're viewing this at https://github.com/teampoltergeist/poltergeist,
10
+ you're reading the documentation for the master branch.
11
+ [View documentation for the latest release
12
+ (1.8.1).](https://github.com/teampoltergeist/poltergeist/tree/v1.8.1)**
13
+
14
+ ## Getting help ##
15
+
16
+ Questions should be posted [on Stack
17
+ Overflow, using the 'poltergeist' tag](http://stackoverflow.com/questions/tagged/poltergeist).
18
+
19
+ Bug reports should be posted [on
20
+ GitHub](https://github.com/teampoltergeist/poltergeist/issues) (and be sure
21
+ to read the bug reporting guidance below).
22
+
23
+ ## Installation ##
24
+
25
+ Add this line to your Gemfile and run `bundle install`:
26
+
27
+ ``` ruby
28
+ gem 'poltergeist'
29
+ ```
30
+
31
+ In your test setup add:
32
+
33
+ ``` ruby
34
+ require 'capybara/poltergeist'
35
+ Capybara.javascript_driver = :poltergeist
36
+ ```
37
+
38
+ If you were previously using the `:rack_test` driver, be aware that
39
+ your app will now run in a separate thread and this can have
40
+ consequences for transactional tests. [See the Capybara README for more
41
+ detail](https://github.com/jnicklas/capybara/blob/master/README.md#transactions-and-database-setup).
42
+
43
+ ## Installing PhantomJS ##
44
+
45
+ You need at least PhantomJS 1.8.1. There are *no other external
46
+ dependencies* (you don't need Qt, or a running X server, etc.)
47
+
48
+ ### Mac ###
49
+
50
+ * *Homebrew*: `brew install phantomjs`
51
+ * *MacPorts*: `sudo port install phantomjs`
52
+ * *Manual install*: [Download this](https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-macosx.zip)
53
+
54
+ ### Linux ###
55
+
56
+ * Download the [32 bit](https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-i686.tar.bz2)
57
+ or [64 bit](https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-x86_64.tar.bz2)
58
+ binary.
59
+ * Extract the tarball and copy `bin/phantomjs` into your `PATH`
60
+
61
+ ### Windows ###
62
+ * Download the [precompiled binary](https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-windows.zip)
63
+ for Windows
64
+
65
+ ### Manual compilation ###
66
+
67
+ Do this as a last resort if the binaries don't work for you. It will
68
+ take quite a long time as it has to build WebKit.
69
+
70
+ * Download [the source tarball](https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-source.zip)
71
+ * Extract and cd in
72
+ * `./build.sh`
73
+
74
+ (See also the [PhantomJS building
75
+ guide](http://phantomjs.org/build.html).)
76
+
77
+ ## Compatibility ##
78
+
79
+ Poltergeist runs on MRI 1.9, JRuby 1.9 and Rubinius 1.9. Poltergeist
80
+ and PhantomJS are currently supported on Mac OS X, Linux, and Windows
81
+ platforms.
82
+
83
+ Ruby 1.8 is no longer supported. The last release to support Ruby 1.8
84
+ was 1.0.2, so you should use that if you still need Ruby 1.8 support.
85
+
86
+ ## Running on a CI ##
87
+
88
+ There are no special steps to take. You don't need Xvfb or any running X
89
+ server at all.
90
+
91
+ [Travis CI](https://travis-ci.org/) and [Codeship](https://codeship.com/) has PhantomJS pre-installed.
92
+
93
+ Depending on your tests, one thing that you may need is some fonts. If
94
+ you're getting errors on a CI that don't occur during development then
95
+ try taking some screenshots - it may well be missing fonts throwing
96
+ things off kilter. Your distro will have various font packages available
97
+ to install.
98
+
99
+ ## What's supported? ##
100
+
101
+ Poltergeist supports all the mandatory features for a Capybara driver,
102
+ and the following optional features:
103
+
104
+ * `page.evaluate_script` and `page.execute_script`
105
+ * `page.within_frame`
106
+ * `page.status_code`
107
+ * `page.response_headers`
108
+ * `page.save_screenshot`
109
+ * `page.driver.render_base64(format, options)`
110
+ * `page.driver.scroll_to(left, top)`
111
+ * `page.driver.basic_authorize(user, password)`
112
+ * `element.native.send_keys(*keys)`
113
+ * window API
114
+ * cookie handling
115
+ * drag-and-drop
116
+
117
+ There are some additional features:
118
+
119
+ ### Taking screenshots with some extensions ###
120
+
121
+ You can grab screenshots of the page at any point by calling
122
+ `save_screenshot('/path/to/file.png')` (this works the same way as the PhantomJS
123
+ render feature, so you can specify other extensions like `.pdf`, `.gif`, etc.)
124
+ Just in case you render pdf it's might be worth to set `driver.paper_size=` with
125
+ settings provided by PhantomJS in [here](https://github.com/ariya/phantomjs/wiki/API-Reference-WebPage#wiki-webpage-paperSize)
126
+
127
+ By default, only the viewport will be rendered (the part of the page that is in
128
+ view). To render the entire page, use `save_screenshot('/path/to/file.png',
129
+ :full => true)`.
130
+
131
+ You also have an ability to render selected element. Pass option `selector` with
132
+ any valid element selector to make a screenshot bounded by that element
133
+ `save_screenshot('/path/to/file.png', :selector => '#id')`.
134
+
135
+ If you need for some reasons base64 encoded screenshot you can simply call
136
+ `render_base64` that will return you encoded image. Additional options are the
137
+ same as for `save_screenshot` except the first argument which is format (:png by
138
+ default, acceptable :png, :gif, :jpeg).
139
+
140
+ ### Clicking precise coordinates ###
141
+
142
+ Sometimes its desirable to click a very specific area of the screen. You can accomplish this with
143
+ `page.driver.click(x, y)`, where x and y are the screen coordinates.
144
+
145
+ ### Remote debugging (experimental) ###
146
+
147
+ If you use the `:inspector => true` option (see below), remote debugging
148
+ will be enabled.
149
+
150
+ When this option is enabled, you can insert `page.driver.debug` into
151
+ your tests to pause the test and launch a browser which gives you the
152
+ WebKit inspector to view your test run with.
153
+
154
+ You can register this debugger driver with a different name and set it
155
+ as the current javascript driver. By example, in your helper file:
156
+
157
+ ```ruby
158
+ Capybara.register_driver :poltergeist_debug do |app|
159
+ Capybara::Poltergeist::Driver.new(app, :inspector => true)
160
+ end
161
+
162
+ # Capybara.javascript_driver = :poltergeist
163
+ Capybara.javascript_driver = :poltergeist_debug
164
+ ```
165
+
166
+ [Read more
167
+ here](http://jonathanleighton.com/articles/2012/poltergeist-0-6-0/)
168
+
169
+ ### Manipulating request headers ###
170
+
171
+ You can manipulate HTTP request headers with these methods:
172
+
173
+ ``` ruby
174
+ page.driver.headers # => {}
175
+ page.driver.headers = { "User-Agent" => "Poltergeist" }
176
+ page.driver.add_headers("Referer" => "https://example.com")
177
+ page.driver.headers # => { "User-Agent" => "Poltergeist", "Referer" => "https://example.com" }
178
+ ```
179
+
180
+ Notice that `headers=` will overwrite already set headers. You should use
181
+ `add_headers` if you want to add a few more. These headers will apply to all
182
+ subsequent HTTP requests (including requests for assets, AJAX, etc). They will
183
+ be automatically cleared at the end of the test. You have ability to set headers
184
+ only for the initial request:
185
+
186
+ ``` ruby
187
+ page.driver.headers = { "User-Agent" => "Poltergeist" }
188
+ page.driver.add_header("Referer", "http://example.com", permanent: false)
189
+ page.driver.headers # => { "User-Agent" => "Poltergeist", "Referer" => "http://example.com" }
190
+ visit(login_path)
191
+ page.driver.headers # => { "User-Agent" => "Poltergeist" }
192
+ ```
193
+
194
+ This way your temporary headers will be sent only for the initial request, all
195
+ subsequent request will only contain your permanent headers.
196
+
197
+ ### Inspecting network traffic ###
198
+
199
+ You can inspect the network traffic (i.e. what resources have been
200
+ loaded) on the current page by calling `page.driver.network_traffic`.
201
+ This returns an array of request objects. A request object has a
202
+ `response_parts` method containing data about the response chunks.
203
+ Please note that network traffic is not cleared when you visit new page.
204
+ You can manually clear the network traffic by calling `page.driver.clear_network_traffic`
205
+ or `page.driver.reset`
206
+
207
+ ### Manipulating cookies ###
208
+
209
+ The following methods are used to inspect and manipulate cookies:
210
+
211
+ * `page.driver.cookies` - a hash of cookies accessible to the current
212
+ page. The keys are cookie names. The values are `Cookie` objects, with
213
+ the following methods: `name`, `value`, `domain`, `path`, `secure?`,
214
+ `httponly?`, `expires`.
215
+ * `page.driver.set_cookie(name, value, options = {})` - set a cookie.
216
+ The options hash can take the following keys: `:domain`, `:path`,
217
+ `:secure`, `:httponly`, `:expires`. `:expires` should be a `Time`
218
+ object.
219
+ * `page.driver.remove_cookie(name)` - remove a cookie
220
+ * `page.driver.clear_cookies` - clear all cookies
221
+
222
+ ### Sending keys ###
223
+
224
+ There's an ability to send arbitrary keys to the element:
225
+
226
+ ``` ruby
227
+ element = find('input#id')
228
+ element.native.send_key('String')
229
+ ```
230
+
231
+ or even more complicated:
232
+
233
+ ``` ruby
234
+ element.native.send_keys('H', 'elo', :Left, 'l') # => 'Hello'
235
+ element.native.send_key(:Enter) # triggers Enter key
236
+ ```
237
+ Since it's implemented natively in PhantomJS this will exactly imitate user
238
+ behavior.
239
+ See more about [sendEvent](http://phantomjs.org/api/webpage/method/send-event.html) and
240
+ [PhantomJS keys](https://github.com/ariya/phantomjs/commit/cab2635e66d74b7e665c44400b8b20a8f225153a)
241
+
242
+ ## Customization ##
243
+
244
+ You can customize the way that Capybara sets up Poltergeist via the following code in your
245
+ test setup:
246
+
247
+ ``` ruby
248
+ Capybara.register_driver :poltergeist do |app|
249
+ Capybara::Poltergeist::Driver.new(app, options)
250
+ end
251
+ ```
252
+
253
+ `options` is a hash of options. The following options are supported:
254
+
255
+ * `:phantomjs` (String) - A custom path to the phantomjs executable
256
+ * `:debug` (Boolean) - When true, debug output is logged to `STDERR`.
257
+ Some debug info from the PhantomJS portion of Poltergeist is also
258
+ output, but this goes to `STDOUT` due to technical limitations.
259
+ * `:logger` (Object responding to `puts`) - When present, debug output is written to this object
260
+ * `:phantomjs_logger` (`IO` object) - Where the `STDOUT` from PhantomJS is written to. This is
261
+ where your `console.log` statements will show up. Default: `STDOUT`
262
+ * `:timeout` (Numeric) - The number of seconds we'll wait for a response
263
+ when communicating with PhantomJS. Default is 30.
264
+ * `:inspector` (Boolean, String) - See 'Remote Debugging', above.
265
+ * `:js_errors` (Boolean) - When false, Javascript errors do not get re-raised in Ruby.
266
+ * `:window_size` (Array) - The dimensions of the browser window in which to test, expressed
267
+ as a 2-element array, e.g. [1024, 768]. Default: [1024, 768]
268
+ * `:phantomjs_options` (Array) - Additional [command line options](http://phantomjs.org/api/command-line.html)
269
+ to be passed to PhantomJS, e.g. `['--load-images=no', '--ignore-ssl-errors=yes']`
270
+ * `:extensions` (Array) - An array of JS files to be preloaded into
271
+ the phantomjs browser. Useful for faking unsupported APIs.
272
+ * `:port` (Fixnum) - The port which should be used to communicate
273
+ with the PhantomJS process. Defaults to a random open port.
274
+
275
+ ### URL Blacklisting ###
276
+
277
+ Poltergeist supports URL blacklisting which allows you
278
+ to prevent scripts from running on designated domains. If you are experiencing
279
+ slower run times, consider creating a URL blacklist of domains that are not
280
+ essential to your testing environment, such as ad networks or analytics.
281
+
282
+ ```ruby
283
+ page.driver.browser.url_blacklist = ['http://www.example.com']
284
+ ```
285
+
286
+ Make sure you set it before each running test, because this setting's cleaned
287
+ up when capybara does reset.
288
+
289
+ ## Troubleshooting ##
290
+
291
+ Unfortunately, the nature of full-stack testing is that things can and
292
+ do go wrong from time to time. This section aims to highlight a number
293
+ of common problems and provide ideas about how you can work around them.
294
+
295
+ ### DeadClient errors ###
296
+
297
+ Sometimes PhantomJS crashes during a test. There are basically two kinds
298
+ of crashes: those that can be reproduced every time, and those that
299
+ occur sporadically and are not easily reproduced.
300
+
301
+ If your crash happens every time, you should read the [PhantomJS crash
302
+ reporting
303
+ guide](http://phantomjs.org/crash-reporting.html) and file
304
+ a bug against PhantomJS. Feel free to also file a bug against
305
+ Poltergeist in case there are workarounds that can be implemented within
306
+ Poltergeist. Also, if lots of Poltergeist users are experiencing the
307
+ same crash then fixing it will move up the priority list.
308
+
309
+ If your crash is sporadic, there is less that can be done. Often these
310
+ issues are very complicated and difficult to track down. It may be that
311
+ the crash has already been fixed in a newer version of WebKit that will
312
+ eventually find its way into PhantomJS. It's still worth reporting your
313
+ bug against PhantomJS, but it's probably not worth filing a bug against
314
+ Poltergeist as there's not much we can do.
315
+
316
+ If you experience sporadic crashes a lot, it may be worth configuring
317
+ your CI to automatically re-run failing tests before reporting a failed
318
+ build.
319
+
320
+ ### MouseEventFailed errors ###
321
+
322
+ When Poltergeist clicks on an element, rather than generating a DOM
323
+ click event, it actually generates a "proper" click. This is much closer
324
+ to what happens when a real user clicks on the page - but it means that
325
+ Poltergeist must scroll the page to where the element is, and work out
326
+ the correct co-ordinates to click. If the element is covered up by
327
+ another element, the click will fail (this is a good thing - because
328
+ your user won't be able to click a covered up element either).
329
+
330
+ Sometimes there can be issues with this behavior. If you have problems,
331
+ it's worth taking screenshots of the page and trying to work out what's
332
+ going on. If your click is failing, but you're not getting a
333
+ `MouseEventFailed` error, then you can turn on the `:debug` option and look
334
+ in the output to see what co-ordinates Poltergeist is using for the
335
+ click. You can then cross-reference this with a screenshot to see if
336
+ something is obviously wrong.
337
+
338
+ If you can't figure out what's going on and just want to work around the
339
+ problem so you can get on with life, consider using a DOM click
340
+ event. For example, if this code is failing:
341
+
342
+ ``` ruby
343
+ click_button "Save"
344
+ ```
345
+
346
+ Then try:
347
+
348
+ ``` ruby
349
+ find_button("Save").trigger('click')
350
+ ```
351
+
352
+ ### Timing problems ###
353
+
354
+ Sometimes tests pass and fail sporadically. This is often because there
355
+ is some problem synchronising events properly. It's often
356
+ straightforward to verify this by adding `sleep` statements into your
357
+ test to allow sufficient time for the page to settle.
358
+
359
+ If you have these types of problems, read through the [Capybara
360
+ documentation on asynchronous
361
+ Javascript](https://github.com/jnicklas/capybara#asynchronous-javascript-ajax-and-friends)
362
+ which explains the tools that Capybara provides for dealing with this.
363
+
364
+ ### Memory leak ###
365
+
366
+ If you run a few capybara sessions manually please make sure you've called
367
+ `session.driver.quit` when you don't need session anymore. Forgetting about this
368
+ causes memory leakage and your system's resources can be exhausted earlier than
369
+ you may expect.
370
+
371
+ ### General troubleshooting hints ###
372
+
373
+ * Configure Poltergeist with `:debug` turned on so you can see its
374
+ communication with PhantomJS.
375
+ * Take screenshots to figure out what the state of your page is when the
376
+ problem occurs.
377
+ * Use the remote web inspector in case it provides any useful insight
378
+ * Consider downloading the Poltergeist source and using `console.log`
379
+ debugging to figure out what's going on inside PhantomJS. (This will
380
+ require an understanding of the Poltergeist source code and PhantomJS,
381
+ so it's only for the committed!)
382
+
383
+ ### Filing a bug ###
384
+
385
+ If you can provide specific steps to reproduce your problem, or have
386
+ specific information that might help other help you track down the
387
+ problem, then please file a bug on Github.
388
+
389
+ Include as much information as possible. For example:
390
+
391
+ * Specific steps to reproduce where possible (failing tests are even
392
+ better)
393
+ * The output obtained from running Poltergeist with `:debug` turned on
394
+ * Screenshots
395
+ * Stack traces if there are any Ruby on Javascript exceptions generated
396
+ * The Poltergeist and PhantomJS version numbers used
397
+ * The operating system name and version used
398
+
399
+ ## Changes ##
400
+
401
+ Version history and a list of next-release features and fixes can be found in
402
+ the [changelog](CHANGELOG.md).
403
+
404
+ ## License ##
405
+
406
+ Copyright (c) 2011-2015 Jonathan Leighton
407
+
408
+ Permission is hereby granted, free of charge, to any person obtaining
409
+ a copy of this software and associated documentation files (the
410
+ "Software"), to deal in the Software without restriction, including
411
+ without limitation the rights to use, copy, modify, merge, publish,
412
+ distribute, sublicense, and/or sell copies of the Software, and to
413
+ permit persons to whom the Software is furnished to do so, subject to
414
+ the following conditions:
415
+
416
+ The above copyright notice and this permission notice shall be
417
+ included in all copies or substantial portions of the Software.
418
+
419
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
420
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
421
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
422
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
423
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
424
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
425
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.