risei 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.txt ADDED
@@ -0,0 +1,8 @@
1
+
2
+ Copyright © 2023 Ed Fallin
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+
6
+ The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,642 @@
1
+
2
+ # RiseiJs
3
+
4
+ ## What RiseiJs is
5
+
6
+ **RiseiJs is a new way to write unit tests that allows you to:**
7
+ * Whip up full test coverage of object-oriented or object-hosted JavaScript in no time.
8
+ * Refactor or replace existing designs without worrying about the cost in past or future test time.
9
+ * Create tests with immediate confidence, because you can't introduce mistakes in test code you write.
10
+
11
+ RiseiJs' `npm`-friendly name is **Risei**.  The package is often referred to as **Rjs** here for brevity.
12
+
13
+ ### Basics of the RiseiJs approach
14
+
15
+ RiseiJs replaces coded tests with simple declarative syntax that's far easier to draft than any other unit-testing approach.
16
+
17
+ Here are two example tests.  `SortModel.countSort()` is being tested with the inputs found in `.in` and the expected output found in `.out`:
18
+
19
+ <div style="padding-left: 1.5rem">
20
+
21
+ ![./usage-examples/Syntax-example.png](./usage-examples/Syntax-example.png)
22
+
23
+ </div>
24
+
25
+ Here is the terminal output of these two example tests.&nbsp; Tests are grouped by class and method.&nbsp; Both expected and actual values are displayed for all tests, to make intended usage obvious at a glance:
26
+
27
+ <div style="padding-left: 1.5rem;">
28
+
29
+ ![./usage-examples/Output-example.png](./usage-examples/Output-example.png)
30
+
31
+ </div>
32
+
33
+ An individual test may appear on one line or multiple lines, depending on how wide the terminal window is.&nbsp; Any failing tests appear in a light red.&nbsp;
34
+
35
+ Test runs also feature a title bar, plus a summary bar at the bottom:
36
+
37
+ <div style="padding-left: 1.5rem;">
38
+
39
+ ![./usage-examples/Summary-example.png](./usage-examples/Summary-example.png)
40
+
41
+ </div>
42
+
43
+
44
+ ## How to use RiseiJs
45
+
46
+ 1. Install RiseiJs the usual way for a development-time `npm` package, using its `npm`-friendly name `risei`:
47
+
48
+ <div style="padding-left: 1.5rem;">
49
+
50
+ ```bash
51
+ npm install --save-dev risei
52
+ ```
53
+
54
+ </div>
55
+
56
+ <details>
57
+ <summary>
58
+ &nbsp; More information
59
+ </summary>
60
+ <br>
61
+
62
+ - RiseiJs is an `npm` package that uses ESM syntax.&nbsp; It only works well with modern versions of Node that automatically support ESM
63
+ - Although ESM is usable with older Node versions using external workarounds, a modern version is highly recommended, and Rjs is not guaranteed to work with older versions.
64
+ - You can install Rjs as a regular dependency if you want using `npm install risei`, but ordinarily this doesn't make sense, and exposing tests in production is generally considered a bad practice.
65
+ - RiseiJs doesn't directly add any security risks to your code, but exposing tests that use it might (as they can for other test frameworks).
66
+
67
+ </details>
68
+
69
+
70
+
71
+ 2. Add a `risei` node to your project's `package.json` to tell Rjs what kind of files to find tests in:
72
+
73
+ <div style="padding-left: 1.5rem;">
74
+
75
+ ```json
76
+ "risei": {
77
+ "tests": "**.rt.js"
78
+ }
79
+ ```
80
+
81
+ </div>
82
+
83
+ <details>
84
+ <summary>
85
+ &nbsp; More options
86
+ </summary>
87
+ <br>
88
+
89
+ - If you prefer another extension for your unit-test files, you can use it instead here.
90
+ - As mentioned earlier, be sure to choose a unique extension for test files.
91
+
92
+ </details>
93
+
94
+
95
+
96
+ 3. Create test files with a `.rt.js` extension.
97
+
98
+ <details>
99
+ <summary>
100
+ &nbsp; More options
101
+ </summary>
102
+ <br>
103
+
104
+ - The extension `.rt.js` is standard, but you can actually use any extension you want, as long as you provide the same extension in the RiseiJs-specific node in `package.json` (covered earlier).
105
+ - Whether you use the standard extension or not, use a unique one to avoid scanning all of your files for tests at each test run.
106
+
107
+ </details>
108
+
109
+
110
+
111
+ 4. Import `ATestSource` from `risei/ATestSource` in each test file, subclass it, and set `tests` to an array of test definitions.
112
+
113
+ <div style="padding-left: 1.5rem;">
114
+
115
+ ```javascript
116
+ import { ATestSource } from "risei/ATestSource";
117
+ import { TargetClass } from "your/path/and/file.js";
118
+
119
+ export TargetClassTests extends ATestSource {
120
+ tests = [ ]; // Not `this.tests`. This array is where test definitions are written.
121
+ }
122
+ ```
123
+
124
+ </div>
125
+
126
+ <details>
127
+ <summary>
128
+ &nbsp; More information
129
+ </summary>
130
+ <br>
131
+
132
+ - Files of tests must be subclasses of `ATestSource`.
133
+ - RiseiJs looks for this class relationship internally, so duck-typing does not work.
134
+ - You have to `import` the class/es under test in the matching test class.
135
+ - Don't use &cross;`this.tests` by accident &mdash; it just causes an exception when tests are run.
136
+
137
+ </details>
138
+
139
+
140
+
141
+ 5. Write each test as a JavaScript object literal in the array with RiseiJs' simple, light syntax:
142
+
143
+ <div style="padding-left: 1.5rem;">
144
+
145
+ ```javascript
146
+ tests = [ ...
147
+ { on: ContainerModelClass, with: [ "a", "b", "c" ], // Target class and constructor args.
148
+ of: "doesContain", // Target method.
149
+ for: "When the input arg is present, returns true.", // Description of test.
150
+ in: [ "c" ], out: true } // Inputs and expected output.
151
+ ... ];
152
+ ```
153
+
154
+ </div>
155
+
156
+ <details>
157
+ <summary>
158
+ &nbsp; Basic test properties and options for each
159
+ </summary>
160
+ <br>
161
+
162
+ <div style="padding-left: 1.5rem;">
163
+
164
+ | Name | Contents |
165
+ |--------|--------------------------------------------------------------------------|
166
+ | `on` | The class under test, as a symbol (already imported into the test file) |
167
+ | `with` | An array of any arguments to pass to the constructor of the tested class |
168
+ | `of` | The name of the method under test, as a string, no `()` used |
169
+ | `for` | A description of what the test proves, for test output |
170
+ | `in` | An array of the input arguments to pass to the tested method |
171
+ | `out` | The expected return value, not in an array |
172
+
173
+ - Properties can be listed in any order within a test definition.
174
+ - There are additional properties for extended functionality (covered later).
175
+ - When there are no parameters for a class' constructor, use an empty array `[ ]` for `.with`.
176
+ - When there are no inputs to a method, use an empty array `[ ]` for `.in`.
177
+ - When the output of a method is an array, freely use an array for `.out`.
178
+ - When there is no output to a method, put the expected value in `.out`, and use special syntax to get the actual value to compare it with (covered later).
179
+ - The property names were chosen to be easy to remember and type.&nbsp; Some of them overlap with JavaScript keywords, but this causes no harm.
180
+ - There are different, long names available to use for each property if wanted (covered later).&nbsp; None of them are JavaScript keywords.
181
+
182
+ </div>
183
+
184
+ </details>
185
+
186
+
187
+
188
+ 6. Write more tests with less syntax by defining parts of what is used in upcoming tests and/or repeating only the properties that are different from the previous test/s:
189
+
190
+ <div style="padding-left: 1.5rem;">
191
+
192
+ ```javascript
193
+ /* All of the following tests are of ContainerModelClass. */
194
+ { on: ContainerModelClass, with: [ "a", "b", "c", "a", "b" ] },
195
+
196
+ /* Two tests for ContainerModelClass .doesContain(). */
197
+ { of: "doesContain" },
198
+ { for: "When the input arg is present, returns true.",
199
+ in: [ "c" ], out: true },
200
+ { for: "When the input arg is not present, returns false.",
201
+ in: [ "d" ], out: false },
202
+
203
+ /* First test for ContainerModelClass .countOf(). */
204
+ { of: "countOf", for: "Returns the number present.", in: [ "b" ], out: 2 }
205
+ ```
206
+
207
+ </div>
208
+
209
+ <details>
210
+ <summary>
211
+ &nbsp; More information
212
+ </summary>
213
+ <br>
214
+
215
+ - Changing the class under test in `.on` wipes out all prior test properties, so the new class has a fresh start.
216
+ - Changing the method under test with a new `.of` wipes out only test properties related to methods, to preserve class values you usually want.
217
+ - You can change individual test properties such as `.with` whenever you want, but by design, they don't revert in the next test.
218
+ - This simplification tactic, called _collapsing forward_, saves a lot of typing and reading.
219
+ - Individual tests remain isolated because class instances, spoofed methods (covered later) and so on are all created anew for each test.
220
+
221
+ </details>
222
+
223
+
224
+
225
+ 7. To isolate any tests with dependencies, spoof the methods depended on, in any objects, with the `.plus` property:
226
+
227
+ <div style="padding-left: 1.5rem;">
228
+
229
+ ```javascript
230
+ { on: CombinerClass, with: [ ],
231
+ of: "combineResults",
232
+ plus: [
233
+ { on: ArraySource, of: "getAllValues", as: [ 7, 8, 9, 10 ] },
234
+ { on: ScalarSource, of: "getValue", as: 12 },
235
+ { on: ObjectSource, of: "getObject", as: { color: "green" } }
236
+ ]
237
+ for: "When called, returns an array of values from sources.",
238
+ in: [ ], out: [ 7, 8, 9, 10, 12, { color: "green" } ] }
239
+ ```
240
+
241
+ - Spoofing definitions collapse forward across tests unless they're replaced with new definitions, or are erased by setting `.plus` to an empty array `[ ]`.
242
+ - Defining new spoofing wipes out all old definitions.
243
+
244
+ </div>
245
+
246
+ <details>
247
+ <summary>
248
+ &nbsp; Spoofing syntax and options
249
+ </summary>
250
+ <br>
251
+
252
+ - Each object in `.plus` consists of the following:
253
+
254
+ <div style="padding-left: 1.5rem;">
255
+
256
+ | Name | Necessary or Optional | Contents |
257
+ |------|-----------------------|---------------------------------------------------------------------------------------------------------------------------|
258
+ | `on` | Optional | Symbol for a type (class); if omitted, the targeted model class is assumed |
259
+ | `of` | Necessary | Name of method to spoof, as a string, `()` not needed |
260
+ | `as` | Optional | Value to return, or nonce implementation; if omitted, an empty method with no return value is used |
261
+
262
+ </div>
263
+
264
+ - You can leave out `.as` when you don't need a return value.&nbsp; An empty method is used (that is, `() => { }`).
265
+ - When necessary, you can provide a function to use in place of the real code, in `.as`.
266
+
267
+
268
+ - This example uses both syntax options:
269
+
270
+ <div style="padding-left: 1.5rem;">
271
+
272
+ ```javascript
273
+ { on: CombinerClass, with: [ ],
274
+ of: "combineResults",
275
+ plus: [
276
+ { on: ArraySource, of: "getAllValues", as: [ 7, 8, 9, 10 ] },
277
+ { on: ScalarSource, of: "getValue" },
278
+ { on: ObjectSource, of: "getObject", as: () => { return { color: "blue" }; } }
279
+ ]
280
+ for: "When called, returns sources' values, skipping any undefineds.",
281
+ in: [ ], out: [ 7, 8, 9, 10, { color: "blue" } ] }
282
+ ```
283
+
284
+ </div>
285
+
286
+ - Spoofed types (like `ArraySource` in the example) have to be imported normally.
287
+ - The properties in the spoof objects within `.plus` don't collapse forward within the array, but must be repeated for each one.
288
+ - You can spoof methods of objects in `.with` and `.in` as well, although you usually don't need to.
289
+ - Properties of spoof objects also have long names (covered later).
290
+
291
+ <details>
292
+ <summary>
293
+ &nbsp; Further spoofing options
294
+ </summary>
295
+ <br>
296
+
297
+ - You can spoof many methods on a class at the same time with an array of partial spoof objects for the `.as` property:
298
+
299
+ <div style="padding-left: 1.5rem;">
300
+
301
+ ```javascript
302
+ plus: [
303
+ { on: SimpleObject, of: "getText", as: "Text" },
304
+ { on: ComplexObject,
305
+ as: [ { of: "getIntegers", as: [ 6, 7, 8 ] },
306
+ { of: "getDoubles", as: [ 6.0, 7.0, 8.0 ] } ]
307
+ }
308
+ ]
309
+ ```
310
+
311
+ </div>
312
+
313
+ - As with simple object-method spoof definitions, `.as` can be omitted in the nested partial spoof objects, with the same effect.
314
+ - You can use this syntax or list multiple full `.on`-`.as`-`.of` objects for a class, with the same effect either way.
315
+
316
+ - You can spoof methods and properties nested inside of other objects using `.` syntax in the `.of` property:
317
+
318
+ <div style="padding-left: 1.5rem;">
319
+
320
+ ```javascript
321
+ plus: [
322
+ { on: SimpleObject, of: "getText", as: "Text" },
323
+ { on: DeepObject, of: "root.branch.leaf.getOptimum", as: 100 }
324
+ ]
325
+ ```
326
+
327
+ </div>
328
+
329
+ </details>
330
+
331
+ </details>
332
+
333
+
334
+
335
+ 8. Run your tests by invoking RiseiJs' `index.js` file:
336
+
337
+ <div style="padding-left: 1.5rem;">
338
+
339
+ ```bash
340
+ node ./node_modules/risei/index.js
341
+ ```
342
+
343
+ </div>
344
+
345
+ <details>
346
+ <summary>
347
+ &nbsp; More information
348
+ </summary>
349
+ <br>
350
+
351
+ - At present, Rjs isn't set up as a script that runs independently, nor as a compiled executable, so you have to run it via its entry-point script.
352
+
353
+ </details>
354
+
355
+
356
+
357
+ 9. Or write the `test` script in `package.json` to invoke `index.js`, to make your life easier:
358
+
359
+ <div style="padding-left: 1.5rem;">
360
+
361
+ ```json
362
+ "scripts": {
363
+ "test": "node ./node_modules/risei/index.js"
364
+ }
365
+ ```
366
+ </div>
367
+
368
+ <details>
369
+ <summary>
370
+ &nbsp; More options
371
+ </summary>
372
+ <br>
373
+
374
+ - You can instead write a unique script for Rjs, though this takes more syntax to call later:
375
+
376
+ <div style="padding-left: 1.5rem;">
377
+
378
+ ```json
379
+ "scripts": {
380
+ "risei": "node ./node_modules/risei/index.js"
381
+ }
382
+ ```
383
+
384
+ </div>
385
+
386
+ - You can define your test script to include the RiseiJs tests alongside other tests if you wish to mix framework usages, which may be appropriate for some scenarios:
387
+
388
+ <div style="padding-left: 1.5rem;">
389
+
390
+ ```json
391
+ "risei": "node ./node_modules/risei/index.js"
392
+ "test": "mocha **/* && risei"
393
+ ```
394
+
395
+ </div>
396
+
397
+ - Of course, if you are used to Linux / Unix scripting, you may also find other techniques to make running tests easier.
398
+
399
+ </details>
400
+
401
+
402
+
403
+ 7. Run that script whenever you want to run tests:
404
+
405
+ <div style="padding-left: 1.5rem;">
406
+
407
+ ```bash
408
+ npm test
409
+ ```
410
+
411
+ </div>
412
+
413
+ <details>
414
+ <summary>
415
+ &nbsp; More options
416
+ </summary>
417
+ <br>
418
+
419
+ - Or run a custom script with longer syntax like this:
420
+
421
+ <div style="padding-left: 1.5rem;">
422
+
423
+ ```bash
424
+ npm run risei
425
+ ```
426
+
427
+ </div>
428
+
429
+ </details>
430
+
431
+
432
+
433
+ ## Advanced RiseiJs usage
434
+
435
+ ### Testing static methods
436
+
437
+ To test a static method, you add an `.and` property to a test, with the value `"static"`:
438
+
439
+ <div style="padding-left: 1.5rem">
440
+
441
+ ```javascript
442
+ { on: StaticModel, with: [] },
443
+
444
+ { of: "getTextProfile",
445
+ for: "Returns accurate profile of arg text.",
446
+ and: "static",
447
+ in: [ "This is a short sentence." ],
448
+ out: { isFullSentence: true, characters: 25, words: 5 }
449
+ }
450
+ ```
451
+
452
+ </div>
453
+
454
+ <details>
455
+ <summary>
456
+ &nbsp; More information
457
+ </summary>
458
+ <br>
459
+
460
+ - The `.and` property is an expansion point for supporting more unusual situations in the future.&nbsp; At present, it only supports static operations.
461
+
462
+ </details>
463
+
464
+
465
+ ### Testing object properties and other non-`return` results
466
+
467
+ To test a value that isn't the exercised code's return value, you add a `.from` property to a test, which can be one of two things:
468
+
469
+ <div style="padding-left: 1.5rem">
470
+
471
+ | Contents of `.from` | Usage |
472
+ |--------------------------------|-------------------------------------------------------------------------|
473
+ | Property name as string | Retrieves the actual from the named property on the test's target class |
474
+ | Specialized function | Retrieves the actual from either its `target` or `test` parameter |
475
+
476
+ - Getting properties, mutated args, and other non-return values is known as _retrieving_.
477
+ - Retrieving definitions collapse forward across tests unless replaced with new definitions, or erased by setting `.from` to an empty array `[ ]`.
478
+
479
+ </div>
480
+
481
+ <details>
482
+ <summary>
483
+ &nbsp; More information
484
+ </summary>
485
+ <br>
486
+
487
+ - Use of `.from` with a property name looks like this:
488
+
489
+ <div style="padding-left: 1.5rem">
490
+
491
+ ```javascript
492
+ { on: StatefulModel, with: [] },
493
+
494
+ { of: "storePolyProduct",
495
+ for: "The result of the calculation is stored as .result.",
496
+ in: [ 10, 8, 9, 6 ], out: 4320, from: "result" },
497
+ ```
498
+
499
+ </div>
500
+
501
+ - Only instance properties can be retrieved by name.&nbsp; For static properties, use `.and` (covered earlier), plus a function as `.from` (covered next).
502
+
503
+ When the contents of `.from` are a function, these are the two parameters:
504
+
505
+ <div style="padding-left: 1.5rem">
506
+
507
+ | Name | Contents |
508
+ |----------|---------------------------------------------------------------------------------------------------|
509
+ | `target` | The instance of the class being tested |
510
+ | `test` | The test definition itself, whose properties may have been mutated by the tested method |
511
+
512
+ </div>
513
+
514
+ - The `test` parameter to a `.from` function contains all of the properties of your test definition, including those that collapsed forward.
515
+ - These properties are available by both short or long names (covered later).
516
+ - The `test.on` property always references the class under test, rather than an instance of it.
517
+
518
+
519
+ - You can write a function for `.from` that uses `test.on` to get the values of static properties, in conjunction with `and: "static"` in the encompassing test.
520
+
521
+
522
+ - Another usage of `.from` function is to look at an input to see if it was changed as expected:
523
+
524
+ <div style="padding-left: 1.5rem">
525
+
526
+ ```javascript
527
+ { on: SecurityModel, with: [] },
528
+
529
+ { of: "addHash",
530
+ for: "The content's hash is added to the input arg a new property.",
531
+ in: [ { content: "SecretValue" }, iterations: 8 ],
532
+ out: { content: "SecretValue", hash: "FasBdQ-fljk%asPcdf" },
533
+ from: (target, test) => { return test.in[0]; }
534
+ },
535
+ ```
536
+
537
+ </div>
538
+
539
+ </details>
540
+
541
+
542
+ ### Property long names
543
+
544
+ Test properties have long names that you can use instead of the short ones if you prefer, mixing together as much as you want.
545
+
546
+
547
+ <details>
548
+ <summary>
549
+ &nbsp; Test properties' short and long names
550
+ </summary>
551
+
552
+ <div style="padding-left: 1.5rem;">
553
+
554
+ | Short Name | Long Name |
555
+ |------------|-----------|
556
+ | `on` | `type` |
557
+ | `with` | `initors` |
558
+ | `of` | `method` |
559
+ | `for` | `nature` |
560
+ | `in` | `inputs` |
561
+ | `out` | `output` |
562
+ | `plus` | `spoofed` |
563
+ | `from` | `source` |
564
+ | `and` | `factors` |
565
+
566
+ </div>
567
+
568
+ </details>
569
+
570
+ <br>
571
+
572
+ <details>
573
+ <summary>
574
+ &nbsp; Spoof properties' short and long names
575
+ </summary>
576
+
577
+ <div style="padding-left: 1.5rem;">
578
+
579
+ | Short Name | Long Name |
580
+ |------------|-----------|
581
+ | `on` | `target` |
582
+ | `of` | `method` |
583
+ | `as` | `output` |
584
+
585
+ </div>
586
+
587
+ </details>
588
+
589
+
590
+ ### Further capabilities of RiseiJs
591
+
592
+ Constructors can be tested with no special test properties or keywords.
593
+ - The method name in `.of` is simply `"constructor"`.
594
+ - Any `.with` args are completely ignored for a constructor test.&nbsp; Only those in the test's `.in` property are used.
595
+ - However, a `.with` must still be provided.&nbsp; It can simply be an empty array `[ ]`.
596
+
597
+
598
+ ### Limitations in RiseiJs
599
+
600
+ The following are not supported at present:
601
+ - Use of `async` syntax
602
+ - Standalone functions and other functionality not built into classes, AKA _loose code_
603
+ - CJS syntax using `require()`
604
+ - Spoofing mixes of properties and methods, such as `something.method.property.method`
605
+
606
+
607
+ ## Troubleshooting
608
+
609
+ Most problems with using RiseiJs are minor mistakes in syntax, or omissions in test definitions:
610
+
611
+ | Error text | Probable cause / fix |
612
+ |----------------------------------------------------------------------------------|-----------------------------------------------------------------------|
613
+ | `"Test loading failed for... SyntaxError: Unexpected token ':'"` | A comma is missing in your tests in the file named. |
614
+ | `"Test loading failed for... SyntaxError: Unexpected token '.'" often means ""` | You used `this.tests = []` instead of `tests = []` in the file named. |
615
+ | Other `... Unexpected token ...` errors | There is some other syntax error in the file named. |
616
+ | Unexpected actual values / passes / fails in test runs | Spoofs, retrievals, or other special conditions from previous tests haven't been replaced / reset.
617
+
618
+ Usually when something is wrong in one test file, other test files still load and run, so a good sign of problems is a sudden decrease in the number of run tests reported.
619
+
620
+
621
+ ## Expanding the RiseiJs world
622
+
623
+ If you find RiseiJs useful, consider spreading the word to other devs, making a donation, making suggestions for improvements, or proposing sponsorships.
624
+
625
+
626
+ ## What the RiseiJs license is
627
+
628
+ RiseiJs is published for use under the terms of the MIT license:
629
+
630
+ <div style="border: solid darkgray 1px; padding: 0.5rem;">
631
+
632
+ <b>RiseiJs Copyright &copy; 2023 Ed Fallin</b>
633
+
634
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
635
+
636
+ The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
637
+
638
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.&nbsp; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
639
+ </div>
640
+
641
+
642
+ &nbsp;