@temporalio/core-bridge 1.9.0-rc.0 → 1.9.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/Cargo.lock +511 -472
- package/Cargo.toml +1 -1
- package/lib/errors.js +6 -6
- package/lib/errors.js.map +1 -1
- package/package.json +5 -5
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/Cargo.toml +4 -0
- package/sdk-core/LICENSE.txt +0 -2
- package/sdk-core/client/Cargo.toml +1 -1
- package/sdk-core/client/src/lib.rs +2 -4
- package/sdk-core/core/Cargo.toml +1 -1
- package/sdk-core/core/src/core_tests/activity_tasks.rs +4 -2
- package/sdk-core/core/src/core_tests/queries.rs +42 -1
- package/sdk-core/core/src/protosext/mod.rs +1 -1
- package/sdk-core/core/src/replay/mod.rs +1 -2
- package/sdk-core/core/src/telemetry/mod.rs +19 -19
- package/sdk-core/core/src/test_help/mod.rs +1 -1
- package/sdk-core/core/src/worker/mod.rs +5 -19
- package/sdk-core/core/src/worker/workflow/history_update.rs +1 -1
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +35 -1
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -1
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +1 -1
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +23 -15
- package/sdk-core/core/src/worker/workflow/mod.rs +8 -12
- package/sdk-core/core/src/worker/workflow/run_cache.rs +9 -15
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -2
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +4 -6
- package/sdk-core/core-api/Cargo.toml +1 -1
- package/sdk-core/fsm/LICENSE.txt +0 -2
- package/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +0 -2
- package/sdk-core/fsm/rustfsm_trait/LICENSE.txt +0 -2
- package/sdk-core/sdk/Cargo.toml +1 -1
- package/sdk-core/sdk/src/workflow_future.rs +2 -2
- package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -4
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +31 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/reset.proto +3 -3
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/export/v1/message.proto +1 -1
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +66 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +6 -2
- package/sdk-core/sdk-core-protos/src/history_info.rs +1 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +1 -1
- package/sdk-core/test-utils/Cargo.toml +1 -0
- package/sdk-core/tests/integ_tests/visibility_tests.rs +4 -4
- package/sdk-core/tests/integ_tests/workflow_tests.rs +141 -3
- package/src/conversions.rs +47 -22
- package/src/runtime.rs +13 -10
- package/ts/index.ts +2 -2
- package/sdk-core/client/LICENSE.txt +0 -23
- package/sdk-core/core/LICENSE.txt +0 -23
- package/sdk-core/core-api/LICENSE.txt +0 -23
- package/sdk-core/sdk/LICENSE.txt +0 -23
- package/sdk-core/sdk-core-protos/LICENSE.txt +0 -23
package/src/conversions.rs
CHANGED
|
@@ -37,17 +37,22 @@ impl ArrayHandleConversionsExt for Handle<'_, JsArray> {
|
|
|
37
37
|
let len = js_vec.len();
|
|
38
38
|
let mut ret_vec = Vec::<String>::with_capacity(len);
|
|
39
39
|
|
|
40
|
-
for i in
|
|
41
|
-
ret_vec
|
|
40
|
+
for i in js_vec.iter().take(len) {
|
|
41
|
+
ret_vec.push(i.downcast_or_throw::<JsString, _>(cx)?.value(cx));
|
|
42
42
|
}
|
|
43
43
|
Ok(ret_vec)
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
pub(crate) type TelemOptsRes = (
|
|
48
|
+
TelemetryOptions,
|
|
49
|
+
Option<Box<dyn FnOnce() -> Arc<dyn CoreMeter> + Send>>,
|
|
50
|
+
);
|
|
51
|
+
|
|
47
52
|
pub trait ObjectHandleConversionsExt {
|
|
48
53
|
fn set_default(&self, cx: &mut FunctionContext, key: &str, value: &str) -> NeonResult<()>;
|
|
49
54
|
fn as_client_options(&self, ctx: &mut FunctionContext) -> NeonResult<ClientOptions>;
|
|
50
|
-
fn as_telemetry_options(&self, cx: &mut FunctionContext) -> NeonResult<
|
|
55
|
+
fn as_telemetry_options(&self, cx: &mut FunctionContext) -> NeonResult<TelemOptsRes>;
|
|
51
56
|
fn as_worker_config(&self, cx: &mut FunctionContext) -> NeonResult<WorkerConfig>;
|
|
52
57
|
fn as_ephemeral_server_config(
|
|
53
58
|
&self,
|
|
@@ -164,7 +169,7 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
164
169
|
.expect("Core server gateway options must be valid"))
|
|
165
170
|
}
|
|
166
171
|
|
|
167
|
-
fn as_telemetry_options(&self, cx: &mut FunctionContext) -> NeonResult<
|
|
172
|
+
fn as_telemetry_options(&self, cx: &mut FunctionContext) -> NeonResult<TelemOptsRes> {
|
|
168
173
|
let mut telemetry_opts = TelemetryOptionsBuilder::default();
|
|
169
174
|
if js_optional_value_getter!(cx, self, "noTemporalPrefixForMetrics", JsBoolean)
|
|
170
175
|
.unwrap_or_default()
|
|
@@ -185,6 +190,8 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
185
190
|
}
|
|
186
191
|
}
|
|
187
192
|
|
|
193
|
+
let mut meter_maker = None;
|
|
194
|
+
|
|
188
195
|
if let Some(ref metrics) = js_optional_getter!(cx, self, "metrics", JsObject) {
|
|
189
196
|
if let Some(ref prom) = js_optional_getter!(cx, metrics, "prometheus", JsObject) {
|
|
190
197
|
if js_optional_getter!(cx, metrics, "otel", JsObject).is_some() {
|
|
@@ -201,16 +208,24 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
201
208
|
Err(_) => {
|
|
202
209
|
return cx.throw_type_error(
|
|
203
210
|
"Invalid telemetryOptions.metrics.prometheus.bindAddress",
|
|
204
|
-
)
|
|
211
|
+
)?;
|
|
205
212
|
}
|
|
206
213
|
};
|
|
207
214
|
|
|
208
|
-
let options = options
|
|
209
|
-
.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
215
|
+
let options = options.build().map_err(|e| {
|
|
216
|
+
cx.throw_type_error::<_, TelemetryOptions>(format!(
|
|
217
|
+
"Failed to build prometheus exporter options: {:?}",
|
|
218
|
+
e
|
|
219
|
+
))
|
|
220
|
+
.unwrap_err()
|
|
221
|
+
})?;
|
|
222
|
+
|
|
223
|
+
meter_maker = Some(Box::new(move || {
|
|
224
|
+
let prom_info = start_prometheus_metric_exporter(options)
|
|
225
|
+
.expect("Failed creating prometheus exporter");
|
|
226
|
+
prom_info.meter as Arc<dyn CoreMeter>
|
|
227
|
+
})
|
|
228
|
+
as Box<dyn FnOnce() -> Arc<dyn CoreMeter> + Send>);
|
|
214
229
|
} else if let Some(ref otel) = js_optional_getter!(cx, metrics, "otel", JsObject) {
|
|
215
230
|
let mut options = OtelCollectorOptionsBuilder::default();
|
|
216
231
|
|
|
@@ -218,7 +233,7 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
218
233
|
match Url::parse(&url) {
|
|
219
234
|
Ok(url) => options.url(url),
|
|
220
235
|
Err(_) => {
|
|
221
|
-
return cx.throw_type_error("Invalid telemetryOptions.metrics.otel.url")
|
|
236
|
+
return cx.throw_type_error("Invalid telemetryOptions.metrics.otel.url");
|
|
222
237
|
}
|
|
223
238
|
};
|
|
224
239
|
|
|
@@ -246,12 +261,19 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
246
261
|
};
|
|
247
262
|
};
|
|
248
263
|
|
|
249
|
-
let options = options
|
|
250
|
-
.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
264
|
+
let options = options.build().map_err(|e| {
|
|
265
|
+
cx.throw_type_error::<_, TelemetryOptions>(format!(
|
|
266
|
+
"Failed to build otlp exporter options: {:?}",
|
|
267
|
+
e
|
|
268
|
+
))
|
|
269
|
+
.unwrap_err()
|
|
270
|
+
})?;
|
|
271
|
+
|
|
272
|
+
meter_maker = Some(Box::new(move || {
|
|
273
|
+
let otlp_exporter =
|
|
274
|
+
build_otlp_metric_exporter(options).expect("Failed to build otlp exporter");
|
|
275
|
+
Arc::new(otlp_exporter) as Arc<dyn CoreMeter>
|
|
276
|
+
}));
|
|
255
277
|
} else {
|
|
256
278
|
cx.throw_type_error(
|
|
257
279
|
"Invalid telemetryOptions.metrics, missing `prometheus` or `otel` option",
|
|
@@ -259,10 +281,13 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
259
281
|
}
|
|
260
282
|
}
|
|
261
283
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
.
|
|
265
|
-
|
|
284
|
+
Ok((
|
|
285
|
+
telemetry_opts.build().map_err(|reason| {
|
|
286
|
+
cx.throw_type_error::<_, TelemetryOptions>(format!("{}", reason))
|
|
287
|
+
.unwrap_err()
|
|
288
|
+
})?,
|
|
289
|
+
meter_maker,
|
|
290
|
+
))
|
|
266
291
|
}
|
|
267
292
|
|
|
268
293
|
fn as_worker_config(&self, cx: &mut FunctionContext) -> NeonResult<WorkerConfig> {
|
package/src/runtime.rs
CHANGED
|
@@ -11,7 +11,7 @@ use std::{
|
|
|
11
11
|
time::{Duration, SystemTime, UNIX_EPOCH},
|
|
12
12
|
};
|
|
13
13
|
use temporal_client::{ClientInitError, ConfiguredClient, TemporalServiceClientWithMetrics};
|
|
14
|
-
use temporal_sdk_core::api::telemetry::
|
|
14
|
+
use temporal_sdk_core::api::telemetry::CoreTelemetry;
|
|
15
15
|
use temporal_sdk_core::CoreRuntime;
|
|
16
16
|
use temporal_sdk_core::{
|
|
17
17
|
ephemeral_server::EphemeralServer as CoreEphemeralServer,
|
|
@@ -116,17 +116,23 @@ pub enum RuntimeRequest {
|
|
|
116
116
|
/// Bridges requests from JS to core and sends responses back to JS using a neon::Channel.
|
|
117
117
|
/// Blocks current thread until a [Shutdown] request is received in channel.
|
|
118
118
|
pub fn start_bridge_loop(
|
|
119
|
-
telemetry_options:
|
|
119
|
+
telemetry_options: TelemOptsRes,
|
|
120
120
|
channel: Arc<Channel>,
|
|
121
121
|
receiver: &mut UnboundedReceiver<RuntimeRequest>,
|
|
122
122
|
) {
|
|
123
123
|
let mut tokio_builder = tokio::runtime::Builder::new_multi_thread();
|
|
124
124
|
tokio_builder.enable_all().thread_name("core");
|
|
125
|
-
let
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
let telem_opts = telemetry_options.0;
|
|
126
|
+
let meter_maker = telemetry_options.1;
|
|
127
|
+
let mut core_runtime =
|
|
128
|
+
CoreRuntime::new(telem_opts, tokio_builder).expect("Failed to create CoreRuntime");
|
|
128
129
|
|
|
129
130
|
core_runtime.tokio_handle().block_on(async {
|
|
131
|
+
if let Some(meter_maker) = meter_maker {
|
|
132
|
+
core_runtime
|
|
133
|
+
.telemetry_mut()
|
|
134
|
+
.attach_late_init_metrics(meter_maker());
|
|
135
|
+
}
|
|
130
136
|
loop {
|
|
131
137
|
let request_option = receiver.recv().await;
|
|
132
138
|
let request = match request_option {
|
|
@@ -147,13 +153,10 @@ pub fn start_bridge_loop(
|
|
|
147
153
|
headers,
|
|
148
154
|
callback,
|
|
149
155
|
} => {
|
|
150
|
-
let
|
|
156
|
+
let mm = core_runtime.telemetry().get_metric_meter();
|
|
151
157
|
core_runtime.tokio_handle().spawn(async move {
|
|
152
158
|
match options
|
|
153
|
-
.connect_no_namespace(
|
|
154
|
-
runtime_clone.telemetry().get_metric_meter(),
|
|
155
|
-
headers.map(|h| Arc::new(RwLock::new(h))),
|
|
156
|
-
)
|
|
159
|
+
.connect_no_namespace(mm, headers.map(|h| Arc::new(RwLock::new(h))))
|
|
157
160
|
.await
|
|
158
161
|
{
|
|
159
162
|
Err(err) => {
|
package/ts/index.ts
CHANGED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
Temporal Core SDK
|
|
2
|
-
|
|
3
|
-
The MIT License
|
|
4
|
-
|
|
5
|
-
Copyright (c) 2021 Temporal Technologies, Inc. All Rights Reserved
|
|
6
|
-
|
|
7
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
-
in the Software without restriction, including without limitation the rights
|
|
10
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
-
furnished to do so, subject to the following conditions:
|
|
13
|
-
|
|
14
|
-
The above copyright notice and this permission notice shall be included in all
|
|
15
|
-
copies or substantial portions of the Software.
|
|
16
|
-
|
|
17
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
-
SOFTWARE.
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
Temporal Core SDK
|
|
2
|
-
|
|
3
|
-
The MIT License
|
|
4
|
-
|
|
5
|
-
Copyright (c) 2021 Temporal Technologies, Inc. All Rights Reserved
|
|
6
|
-
|
|
7
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
-
in the Software without restriction, including without limitation the rights
|
|
10
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
-
furnished to do so, subject to the following conditions:
|
|
13
|
-
|
|
14
|
-
The above copyright notice and this permission notice shall be included in all
|
|
15
|
-
copies or substantial portions of the Software.
|
|
16
|
-
|
|
17
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
-
SOFTWARE.
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
Temporal Core SDK
|
|
2
|
-
|
|
3
|
-
The MIT License
|
|
4
|
-
|
|
5
|
-
Copyright (c) 2021 Temporal Technologies, Inc. All Rights Reserved
|
|
6
|
-
|
|
7
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
-
in the Software without restriction, including without limitation the rights
|
|
10
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
-
furnished to do so, subject to the following conditions:
|
|
13
|
-
|
|
14
|
-
The above copyright notice and this permission notice shall be included in all
|
|
15
|
-
copies or substantial portions of the Software.
|
|
16
|
-
|
|
17
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
-
SOFTWARE.
|
package/sdk-core/sdk/LICENSE.txt
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
Temporal Core SDK
|
|
2
|
-
|
|
3
|
-
The MIT License
|
|
4
|
-
|
|
5
|
-
Copyright (c) 2021 Temporal Technologies, Inc. All Rights Reserved
|
|
6
|
-
|
|
7
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
-
in the Software without restriction, including without limitation the rights
|
|
10
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
-
furnished to do so, subject to the following conditions:
|
|
13
|
-
|
|
14
|
-
The above copyright notice and this permission notice shall be included in all
|
|
15
|
-
copies or substantial portions of the Software.
|
|
16
|
-
|
|
17
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
-
SOFTWARE.
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
Temporal Core SDK
|
|
2
|
-
|
|
3
|
-
The MIT License
|
|
4
|
-
|
|
5
|
-
Copyright (c) 2021 Temporal Technologies, Inc. All Rights Reserved
|
|
6
|
-
|
|
7
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
-
in the Software without restriction, including without limitation the rights
|
|
10
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
-
furnished to do so, subject to the following conditions:
|
|
13
|
-
|
|
14
|
-
The above copyright notice and this permission notice shall be included in all
|
|
15
|
-
copies or substantial portions of the Software.
|
|
16
|
-
|
|
17
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
-
SOFTWARE.
|