@sdeverywhere/cli 0.7.9 → 0.7.11
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/README.md +264 -4
- package/package.json +11 -11
- package/src/c/model.c +38 -2
- package/src/c/sde.h +3 -1
- package/src/sde-compare.js +1 -1
- package/src/sde-log.js +1 -1
- package/src/utils.js +1 -1
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -1,13 +1,273 @@
|
|
|
1
1
|
# @sdeverywhere/cli
|
|
2
2
|
|
|
3
|
-
This package contains the `sde` command line interface for the SDEverywhere
|
|
4
|
-
suite of tools.
|
|
3
|
+
This package contains the `sde` command line interface for the [SDEverywhere](https://github.com/climateinteractive/SDEverywhere) suite of tools.
|
|
5
4
|
|
|
6
5
|
SDEverywhere can be used to translate System Dynamics models from Vensim to C and WebAssembly.
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
For more details on the full suite of tools and libraries provided in SDEverywhere, refer to the top-level [README](https://github.com/climateinteractive/SDEverywhere) in the SDEverywhere repository.
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
For instructions on using the `sde` command line tool provided in this package, refer to the ["Usage"](#usage) section below.
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
The best way to get started with SDEverywhere is to follow the [Quick Start](https://github.com/climateinteractive/SDEverywhere#quick-start) instructions.
|
|
14
|
+
If you follow those instructions, the `@sdeverywhere/cli` package and `sde` tool will be added to your project automatically, in which case you can skip the next section and jump straight to the ["Usage"](#usage) section below.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
If you are building a JavaScript-based library or application, it is recommended that you install the `cli` package locally (in the `devDependencies` section of your `package.json` file).
|
|
19
|
+
This allows you to use a version of the `cli` package that is specific to your project:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npm install --save-dev @sdeverywhere/cli
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If you are using SDEverywhere only to generate C code (using the more advanced `sde` commands listed below), then it is acceptable to install the package "globally":
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npm install -g @sdeverywhere/cli
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
If you installed the `cli` package globally (see ["Install"](#install) section above), you can run the `sde` command directly.
|
|
34
|
+
|
|
35
|
+
If you installed the `cli` package locally (i.e., you followed the "Quick Start" instructions and/or installed it as a dev dependency in your `package.json`), you can run the `sde` command via `npx`, for example:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
npx sde <args>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Basic commands
|
|
42
|
+
|
|
43
|
+
Note: A string surrounded by curly braces `{like this}` indicates a placeholder that you should fill in with the appropriate value.
|
|
44
|
+
|
|
45
|
+
Use `sde -h` to see a list of all commands.
|
|
46
|
+
|
|
47
|
+
Use `sde {command}` to see options for a command.
|
|
48
|
+
|
|
49
|
+
It is usually easiest to run these commands from the directory where the `.mdl` file is located.
|
|
50
|
+
The `{model}` placeholder can be the model filename, for instance `arrays.mdl`, or simply the model name `arrays`.
|
|
51
|
+
|
|
52
|
+
If you are not running from the model directory, you can give a full pathname to locate the `.mdl` file anywhere on the system.
|
|
53
|
+
|
|
54
|
+
By default, SDEverywhere will create a `build` directory in your model directory to hold the generated code and the compiled model.
|
|
55
|
+
If you run the model, it will also create an `output` directory by default.
|
|
56
|
+
You can specify other directories with command options.
|
|
57
|
+
|
|
58
|
+
#### Generate C code that outputs all variables with no inputs
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
sde generate --genc {model}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Generate C code that uses a specified set of inputs and outputs
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
sde generate --genc --spec {model}_spec.json {model}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
#### Start a local development builder/server
|
|
71
|
+
|
|
72
|
+
The `sde dev` command is great for local development of a web application.
|
|
73
|
+
It will start a builder process that rebuilds your app and runs QA checks against your model any time you save changes to your `mdl` file.
|
|
74
|
+
You can leave the builder running while developing your model in Vensim.
|
|
75
|
+
The app and model-check tabs in your browser will refresh automatically whenever you save changes in Vensim or make edits to your application code.
|
|
76
|
+
|
|
77
|
+
See [`examples/hello-world`](https://github.com/climateinteractive/SDEverywhere/tree/main/examples/hello-world) for a simple example of an `sde.config.js` file.
|
|
78
|
+
You can also follow the [Quick Start](https://github.com/climateinteractive/SDEverywhere/tree/main/examples/sir#quick-start) instructions for `examples/sir`, which will generate a more complete example of an `sde.config.js` file.
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
sde dev [--config sde.config.js] [--verbose]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### Generate a JS bundle that can be deployed on a web server
|
|
85
|
+
|
|
86
|
+
After using the `sde dev` command described above, you can use `sde bundle` to generate a production-ready version of your web application that can be deployed on any web server.
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
sde bundle [--config sde.config.js] [--verbose]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Advanced commands
|
|
93
|
+
|
|
94
|
+
#### List a model's variables
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
sde generate --list {model}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### Preprocess a model to remove macros and tabbed arrays to removals.txt
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
sde generate --preprocess {model}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### Compile the C code into an executable in the build directory
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
sde compile {model}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### Run the executable and capture output into a text file in the output directory
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
sde exec {model} {arguments}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### Convert the SDEverywhere output file to a DAT file in the output directory
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
sde log --dat output/{model}.txt
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### Compare a previously exported Vensim DAT file to SDEverywhere output
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
sde compare {model}.dat output/{model}.dat
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### Generate C code and compile it in the build directory
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
sde build {model}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### Build C code and run the model
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
sde run {model}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### Run the model and compare its output to a previously exported Vensim DAT file
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
sde test {model}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### Delete the build and output directories
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
sde clean {model}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### Print variable dependencies
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
sde causes {model} {C variable name}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### Convert variable names to C format
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
sde names {model} {Vensim names file}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### Print the SDEverywhere home directory
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
sde which
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Configuration files
|
|
173
|
+
|
|
174
|
+
_NOTE:_ The following sections refer to "model specification files" (or "spec files" as a shorthand).
|
|
175
|
+
These JSON spec files are generally used by the lower-level `sde` commands, such as `sde generate`.
|
|
176
|
+
We are gradually adding support for a more flexible configuration file format (`sde.config.js`) that works with newer commands such as `sde dev` and `sde bundle`.
|
|
177
|
+
We hope to unify these configuration file formats soon to eliminate any confusion about which file format can be used with which command (see related issue [#327](https://github.com/climateinteractive/SDEverywhere/issues/327)).
|
|
178
|
+
|
|
179
|
+
#### Specify input and output variables
|
|
180
|
+
|
|
181
|
+
Most applications do not require all variables in the output.
|
|
182
|
+
And we usually want to designate some constant variables as inputs.
|
|
183
|
+
In SDEverywhere, this is done with a model specification JSON file.
|
|
184
|
+
The conventional name is `{model}_spec.json`.
|
|
185
|
+
|
|
186
|
+
First, create a model specification file that gives the Vensim names of input and output variables of interest.
|
|
187
|
+
Be sure to include `Time` first among the output variables.
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"inputVars": ["Reference predators", "Reference prey"],
|
|
192
|
+
"outputVars": ["Time", "Predators Y", "Prey X"]
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### Specify external data sources
|
|
197
|
+
|
|
198
|
+
Add a `directData` section to the spec file to have SDEverywhere read data from an Excel file into lookups with a variable name prefix.
|
|
199
|
+
There is an example in the `directdata` sample model.
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
"directData": {
|
|
203
|
+
"?data": "data.xlsx"
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### Specify equations to remove from the model
|
|
208
|
+
|
|
209
|
+
When SDEverywhere cannot handle a certain Vensim construct yet, you will need to remove equations that use the construct from the model, convert it by hand into something that SDEverywhere can handle, and then insert it back into the model.
|
|
210
|
+
To have the preprocessor remove equations from the model into a `removals.txt` file, specify substrings to match in the equation in the `removalKeys` section.
|
|
211
|
+
Macros and `TABBED ARRAY` equations are already automatically removed by the preprocessor.
|
|
212
|
+
|
|
213
|
+
For instance, you could key on the variable name in the equation definition.
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
"removalKeys": [
|
|
217
|
+
"varname1 =",
|
|
218
|
+
"varname2 ="
|
|
219
|
+
]
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### Generating, compiling, running, and testing the C code
|
|
223
|
+
|
|
224
|
+
To generate C code using the `--spec` argument, enter the following command:
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
sde generate --genc --spec {model}_spec.json {model}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
SDE allows for validation against Vensim output.
|
|
231
|
+
Before running the C file, it is useful to generate the Vensim data so you can ensure the C code is valid and reproduces the same results as Vensim.
|
|
232
|
+
To make the Vensim output, run the model in 64-bit Vensim and export the run in DAT format to the `{model}.dat` file in the model directory.
|
|
233
|
+
|
|
234
|
+
The `sde test` command generates baseline C code that outputs all variables with no inputs.
|
|
235
|
+
It then compiles the C code and runs it.
|
|
236
|
+
The output is captured and converted into DAT format in the `output/{model}.dat` file.
|
|
237
|
+
This is compared to Vensim run exported to a `{model}.dat` file in the model directory.
|
|
238
|
+
All values that differ by a factor of 1e-5 or more are listed with the variance.
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
sde test {model}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### Setting inputs
|
|
245
|
+
|
|
246
|
+
SDEverywhere generates code that runs the model using the constants defined in the model.
|
|
247
|
+
To explore model behavior, the user changes the values of constants we call "input variables" and runs the model again.
|
|
248
|
+
|
|
249
|
+
There is a `setInputs` implementation in the generated code that gets called at initialization.
|
|
250
|
+
It takes a string with serialized input values and sets variable values from it.
|
|
251
|
+
The serialization format depends on the needs of your application.
|
|
252
|
+
You can replace `setInputs` if you want to use a different serialization form.
|
|
253
|
+
The input variables are listed in the `inputVars` section of the spec file.
|
|
254
|
+
Look at the `arrays` model for an example.
|
|
255
|
+
|
|
256
|
+
The generated format minimizes the amount of data on the wire for web applications.
|
|
257
|
+
It parses index-value pairs sent in a compact format that looks like this: `0:3.14 6:42`.
|
|
258
|
+
That is, the values are separated by spaces, and each pair has an index number, a colon, and a floating point number.
|
|
259
|
+
|
|
260
|
+
The zero-based index maps into a static array of input variable pointers held in the function.
|
|
261
|
+
These are used to set the value directly into the static `double` variable in the generated code.
|
|
262
|
+
|
|
263
|
+
#### Inserting a file into the model
|
|
264
|
+
|
|
265
|
+
Some constructs like macros are not supported by SDEverywhere.
|
|
266
|
+
They are removed from the model by the preprocessor into the `removals.txt` file.
|
|
267
|
+
You can edit these constructs into a form that SDEverywhere supports and insert them back into the model.
|
|
268
|
+
Create a file called `mdl-edits.txt` in the model directory with the constructs to insert.
|
|
269
|
+
For instance, manually expand macros and place them into the `mdl-edits.txt` file.
|
|
270
|
+
The preprocessor will read this file and insert its contents unchanged into the beginning of the model.
|
|
11
271
|
|
|
12
272
|
## License
|
|
13
273
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdeverywhere/cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.11",
|
|
4
4
|
"description": "Contains the `sde` command line interface for the SDEverywhere tool suite.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -10,9 +10,16 @@
|
|
|
10
10
|
"bin": {
|
|
11
11
|
"sde": "src/main.js"
|
|
12
12
|
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"lint": "eslint . --max-warnings 0",
|
|
15
|
+
"prettier:check": "prettier --check .",
|
|
16
|
+
"prettier:fix": "prettier --write .",
|
|
17
|
+
"precommit": "../../scripts/precommit",
|
|
18
|
+
"ci:build": "run-s lint prettier:check"
|
|
19
|
+
},
|
|
13
20
|
"dependencies": {
|
|
14
|
-
"@sdeverywhere/build": "^0.3.
|
|
15
|
-
"@sdeverywhere/compile": "^0.7.
|
|
21
|
+
"@sdeverywhere/build": "^0.3.2",
|
|
22
|
+
"@sdeverywhere/compile": "^0.7.7",
|
|
16
23
|
"bufx": "^1.0.5",
|
|
17
24
|
"byline": "^5.0.0",
|
|
18
25
|
"ramda": "^0.27.0",
|
|
@@ -29,12 +36,5 @@
|
|
|
29
36
|
},
|
|
30
37
|
"bugs": {
|
|
31
38
|
"url": "https://github.com/climateinteractive/SDEverywhere/issues"
|
|
32
|
-
},
|
|
33
|
-
"scripts": {
|
|
34
|
-
"lint": "eslint . --max-warnings 0",
|
|
35
|
-
"prettier:check": "prettier --check .",
|
|
36
|
-
"prettier:fix": "prettier --write .",
|
|
37
|
-
"precommit": "../../scripts/precommit",
|
|
38
|
-
"ci:build": "run-s lint prettier:check"
|
|
39
39
|
}
|
|
40
|
-
}
|
|
40
|
+
}
|
package/src/c/model.c
CHANGED
|
@@ -8,6 +8,14 @@
|
|
|
8
8
|
struct timespec startTime, finishTime;
|
|
9
9
|
#endif
|
|
10
10
|
|
|
11
|
+
// For each output variable specified in the indices buffer, there
|
|
12
|
+
// are 4 index values:
|
|
13
|
+
// varIndex
|
|
14
|
+
// subIndex0
|
|
15
|
+
// subIndex1
|
|
16
|
+
// subIndex2
|
|
17
|
+
#define INDICES_PER_OUTPUT 4
|
|
18
|
+
|
|
11
19
|
// The special _time variable is not included in .mdl files.
|
|
12
20
|
double _time;
|
|
13
21
|
|
|
@@ -17,6 +25,7 @@ size_t outputIndex = 0;
|
|
|
17
25
|
|
|
18
26
|
// Output data buffer used by `runModelWithBuffers`
|
|
19
27
|
double* outputBuffer = NULL;
|
|
28
|
+
int32_t* outputIndexBuffer = NULL;
|
|
20
29
|
size_t outputVarIndex = 0;
|
|
21
30
|
size_t numSavePoints = 0;
|
|
22
31
|
size_t savePointIndex = 0;
|
|
@@ -66,6 +75,13 @@ double getSaveper() {
|
|
|
66
75
|
return _saveper;
|
|
67
76
|
}
|
|
68
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Return the constant `maxOutputIndices` value.
|
|
80
|
+
*/
|
|
81
|
+
int getMaxOutputIndices() {
|
|
82
|
+
return maxOutputIndices;
|
|
83
|
+
}
|
|
84
|
+
|
|
69
85
|
char* run_model(const char* inputs) {
|
|
70
86
|
// run_model does everything necessary to run the model with the given inputs.
|
|
71
87
|
// It may be called multiple times. Call finish() after all runs are complete.
|
|
@@ -102,13 +118,15 @@ char* run_model(const char* inputs) {
|
|
|
102
118
|
* (where tN is the last time in the range), the second variable outputs will begin,
|
|
103
119
|
* and so on.
|
|
104
120
|
*/
|
|
105
|
-
void runModelWithBuffers(double* inputs, double* outputs) {
|
|
121
|
+
void runModelWithBuffers(double* inputs, double* outputs, int32_t* outputIndices) {
|
|
106
122
|
outputBuffer = outputs;
|
|
123
|
+
outputIndexBuffer = outputIndices;
|
|
107
124
|
initConstants();
|
|
108
125
|
setInputsFromBuffer(inputs);
|
|
109
126
|
initLevels();
|
|
110
127
|
run();
|
|
111
128
|
outputBuffer = NULL;
|
|
129
|
+
outputIndexBuffer = NULL;
|
|
112
130
|
}
|
|
113
131
|
|
|
114
132
|
void run() {
|
|
@@ -137,7 +155,25 @@ void run() {
|
|
|
137
155
|
numSavePoints = (size_t)(round((_final_time - _initial_time) / _saveper)) + 1;
|
|
138
156
|
}
|
|
139
157
|
outputVarIndex = 0;
|
|
140
|
-
|
|
158
|
+
if (outputIndexBuffer != NULL) {
|
|
159
|
+
// Store the outputs as specified in the current output index buffer
|
|
160
|
+
for (size_t i = 0; i < maxOutputIndices; i++) {
|
|
161
|
+
size_t indexBufferOffset = i * INDICES_PER_OUTPUT;
|
|
162
|
+
size_t varIndex = (size_t)outputIndexBuffer[indexBufferOffset];
|
|
163
|
+
if (varIndex > 0) {
|
|
164
|
+
size_t subIndex0 = (size_t)outputIndexBuffer[indexBufferOffset + 1];
|
|
165
|
+
size_t subIndex1 = (size_t)outputIndexBuffer[indexBufferOffset + 2];
|
|
166
|
+
size_t subIndex2 = (size_t)outputIndexBuffer[indexBufferOffset + 3];
|
|
167
|
+
storeOutput(varIndex, subIndex0, subIndex1, subIndex2);
|
|
168
|
+
} else {
|
|
169
|
+
// Stop when we reach the first zero index
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
// Store the normal outputs
|
|
175
|
+
storeOutputData();
|
|
176
|
+
}
|
|
141
177
|
savePointIndex++;
|
|
142
178
|
}
|
|
143
179
|
if (step == lastStep) break;
|
package/src/c/sde.h
CHANGED
|
@@ -42,6 +42,7 @@ EXTERN double _epsilon;
|
|
|
42
42
|
|
|
43
43
|
// Internal variables
|
|
44
44
|
EXTERN const int numOutputs;
|
|
45
|
+
EXTERN const int maxOutputIndices;
|
|
45
46
|
|
|
46
47
|
// Standard simulation control parameters
|
|
47
48
|
EXTERN double _time;
|
|
@@ -55,7 +56,7 @@ double getInitialTime(void);
|
|
|
55
56
|
double getFinalTime(void);
|
|
56
57
|
double getSaveper(void);
|
|
57
58
|
char* run_model(const char* inputs);
|
|
58
|
-
void runModelWithBuffers(double* inputs, double* outputs);
|
|
59
|
+
void runModelWithBuffers(double* inputs, double* outputs, int32_t* outputIndices);
|
|
59
60
|
void run(void);
|
|
60
61
|
void startOutput(void);
|
|
61
62
|
void outputVar(double value);
|
|
@@ -69,6 +70,7 @@ void setInputsFromBuffer(double *inputData);
|
|
|
69
70
|
void evalAux(void);
|
|
70
71
|
void evalLevels(void);
|
|
71
72
|
void storeOutputData(void);
|
|
73
|
+
void storeOutput(size_t varIndex, size_t subIndex0, size_t subIndex1, size_t subIndex2);
|
|
72
74
|
const char* getHeader(void);
|
|
73
75
|
|
|
74
76
|
#ifdef __cplusplus
|
package/src/sde-compare.js
CHANGED
package/src/sde-log.js
CHANGED
package/src/utils.js
CHANGED
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2016-2022 Todd Fincannon and Climate Interactive / New Venture Fund
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|