askui 0.7.1 → 0.7.2

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.
Files changed (45) hide show
  1. package/dist/cjs/core/annotation/annotation-json.d.ts +5 -0
  2. package/dist/cjs/core/annotation/annotation-json.js +2 -0
  3. package/dist/cjs/core/inference-response/inference-response.d.ts +7 -11
  4. package/dist/cjs/core/inference-response/inference-response.js +8 -13
  5. package/dist/cjs/core/inference-response/invalid-model-type-error.d.ts +4 -0
  6. package/dist/cjs/core/inference-response/invalid-model-type-error.js +9 -0
  7. package/dist/cjs/core/inference-response/model-type.d.ts +1 -0
  8. package/dist/cjs/core/inference-response/model-type.js +2 -0
  9. package/dist/cjs/core/model/test-case-dto/custom-element.spec.d.ts +1 -0
  10. package/dist/cjs/core/model/test-case-dto/custom-element.spec.js +53 -0
  11. package/dist/cjs/execution/dsl.spec.d.ts +1 -0
  12. package/dist/cjs/execution/dsl.spec.js +75 -0
  13. package/dist/cjs/execution/inference-client.d.ts +1 -0
  14. package/dist/cjs/execution/inference-client.js +17 -8
  15. package/dist/cjs/execution/read-environment-credentials.spec.d.ts +1 -0
  16. package/dist/cjs/execution/read-environment-credentials.spec.js +11 -0
  17. package/dist/cjs/lib/ui-controller-args.spec.d.ts +1 -0
  18. package/dist/cjs/lib/ui-controller-args.spec.js +23 -0
  19. package/dist/cjs/utils/http/credentials.spec.d.ts +1 -0
  20. package/dist/cjs/utils/http/credentials.spec.js +11 -0
  21. package/dist/cjs/utils/http/http-client-got.d.ts +5 -1
  22. package/dist/cjs/utils/http/http-client-got.js +12 -4
  23. package/dist/esm/core/annotation/annotation-json.d.ts +5 -0
  24. package/dist/esm/core/annotation/annotation-json.js +1 -0
  25. package/dist/esm/core/inference-response/inference-response.d.ts +7 -11
  26. package/dist/esm/core/inference-response/inference-response.js +8 -13
  27. package/dist/esm/core/inference-response/invalid-model-type-error.d.ts +4 -0
  28. package/dist/esm/core/inference-response/invalid-model-type-error.js +5 -0
  29. package/dist/esm/core/inference-response/model-type.d.ts +1 -0
  30. package/dist/esm/core/inference-response/model-type.js +1 -0
  31. package/dist/esm/core/model/test-case-dto/custom-element.spec.d.ts +1 -0
  32. package/dist/esm/core/model/test-case-dto/custom-element.spec.js +51 -0
  33. package/dist/esm/execution/dsl.spec.d.ts +1 -0
  34. package/dist/esm/execution/dsl.spec.js +73 -0
  35. package/dist/esm/execution/inference-client.d.ts +1 -0
  36. package/dist/esm/execution/inference-client.js +17 -8
  37. package/dist/esm/execution/read-environment-credentials.spec.d.ts +1 -0
  38. package/dist/esm/execution/read-environment-credentials.spec.js +9 -0
  39. package/dist/esm/lib/ui-controller-args.spec.d.ts +1 -0
  40. package/dist/esm/lib/ui-controller-args.spec.js +21 -0
  41. package/dist/esm/utils/http/credentials.spec.d.ts +1 -0
  42. package/dist/esm/utils/http/credentials.spec.js +9 -0
  43. package/dist/esm/utils/http/http-client-got.d.ts +5 -1
  44. package/dist/esm/utils/http/http-client-got.js +12 -4
  45. package/package.json +1 -1
@@ -0,0 +1,5 @@
1
+ import { DetectedElement } from '../model/annotation-result/detected-element';
2
+ export interface AnnotationJson {
3
+ image: string;
4
+ objects: DetectedElement[];
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,15 +1,11 @@
1
1
  import { ControlCommand } from '../ui-control-commands/control-command';
2
2
  import { Annotation } from '../annotation/annotation';
3
- export declare class InferenceResponse {
4
- type: string;
5
- data: ControlCommand | Annotation;
6
- constructor(type: string, data: ControlCommand | Annotation);
7
- static fromJson(json: unknown, resizeRatio?: number, image?: string): ControlCommand | Annotation;
8
- static createModels(type: string, data: ControlCommand | Annotation, resizeRatio: number, image?: string): ControlCommand | Annotation;
9
- static models: Models;
3
+ import { ModelType } from './model-type';
4
+ export interface InferenceResponseBody {
5
+ type: ModelType;
6
+ data: ModelType extends 'COMMANDS' ? ControlCommand : Annotation;
10
7
  }
11
- interface Models {
12
- DETECTED_ELEMENTS: CallableFunction;
13
- COMMANDS: CallableFunction;
8
+ export declare class InferenceResponse {
9
+ static fromJson(json: InferenceResponseBody, resizeRatio?: number, image?: string): ControlCommand | Annotation;
10
+ static createModels(type: ModelType, data: ModelType extends 'COMMANDS' ? ControlCommand : Annotation, resizeRatio: number, image?: string): ControlCommand | Annotation;
14
11
  }
15
- export {};
@@ -3,23 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InferenceResponse = void 0;
4
4
  const control_command_1 = require("../ui-control-commands/control-command");
5
5
  const annotation_1 = require("../annotation/annotation");
6
+ const invalid_model_type_error_1 = require("./invalid-model-type-error");
6
7
  class InferenceResponse {
7
- constructor(type, data) {
8
- this.type = type;
9
- this.data = data;
10
- }
11
8
  static fromJson(json, resizeRatio = 1, image) {
12
- const inferenceResponse = json;
13
- return this.createModels(inferenceResponse.type, inferenceResponse.data, resizeRatio, image);
9
+ return this.createModels(json.type, json.data, resizeRatio, image);
14
10
  }
15
11
  static createModels(type, data, resizeRatio, image) {
16
- return this.models[type](data, resizeRatio, image);
12
+ if (type === 'COMMANDS')
13
+ return control_command_1.ControlCommand.fromJson(data, resizeRatio);
14
+ if (type === 'DETECTED_ELEMENTS') {
15
+ return annotation_1.Annotation.fromJson({ image, detected_elements: data.detected_elements }, resizeRatio);
16
+ }
17
+ throw new invalid_model_type_error_1.InvalidModelTypeError(type);
17
18
  }
18
19
  }
19
20
  exports.InferenceResponse = InferenceResponse;
20
- InferenceResponse.models = {
21
- DETECTED_ELEMENTS: (data, resizeRatio, image) => annotation_1.Annotation
22
- .fromJson({ image, detected_elements: data.detected_elements }, resizeRatio),
23
- COMMANDS: (data, resizeRatio) => control_command_1.ControlCommand
24
- .fromJson(data, resizeRatio),
25
- };
@@ -0,0 +1,4 @@
1
+ import { ModelType } from './model-type';
2
+ export declare class InvalidModelTypeError extends Error {
3
+ constructor(type: ModelType);
4
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InvalidModelTypeError = void 0;
4
+ class InvalidModelTypeError extends Error {
5
+ constructor(type) {
6
+ super(`Invalid model type: ${type}`);
7
+ }
8
+ }
9
+ exports.InvalidModelTypeError = InvalidModelTypeError;
@@ -0,0 +1 @@
1
+ export declare type ModelType = 'DETECTED_ELEMENTS' | 'COMMANDS';
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const custom_element_1 = require("./custom-element");
13
+ const base64ImageString = 'data:image/png;base64,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';
14
+ describe('CustomElement', () => {
15
+ describe('fromJsonWithImagePathOrImage', () => {
16
+ test('should return CustomElement if CustomElement created from JSON is valid', () => __awaiter(void 0, void 0, void 0, function* () {
17
+ const expected = new custom_element_1.CustomElement(base64ImageString, 'Dummy_element', 0.7, 10, 'RGB', [{ x: 0, y: 1 }, { x: 1, y: 2 }, { x: 3, y: 4 }]);
18
+ const actual = yield custom_element_1.CustomElement.fromJsonWithImagePathOrImage({
19
+ customImage: base64ImageString,
20
+ name: 'Dummy_element',
21
+ threshold: 0.7,
22
+ rotationDegreePerStep: 10,
23
+ imageCompareFormat: 'RGB',
24
+ mask: [{ x: 0, y: 1 }, { x: 1, y: 2 }, { x: 3, y: 4 }],
25
+ });
26
+ expect(actual).toStrictEqual(expected);
27
+ }));
28
+ test('should throw ValidationError if threshold is invalid', () => {
29
+ expect(() => {
30
+ const customElement = new custom_element_1.CustomElement(base64ImageString, 'Dummy_element', 1.1, 10, 'RGB', [{ x: 0, y: 1 }, { x: 1, y: 2 }, { x: 3, y: 4 }]);
31
+ customElement.validate();
32
+ }).toThrow('threshold must be less than or equal to 1');
33
+ });
34
+ test('should throw ValidationError if rotationDegreePerStep is invalid', () => {
35
+ expect(() => {
36
+ const customElement = new custom_element_1.CustomElement(base64ImageString, 'Dummy_element', 0.9, -90, 'RGB', [{ x: 0, y: 1 }, { x: 1, y: 2 }, { x: 3, y: 4 }]);
37
+ customElement.validate();
38
+ }).toThrow('rotationDegreePerStep must be greater than or equal to 0');
39
+ });
40
+ test('should throw ValidationError if mask is invalid', () => {
41
+ expect(() => {
42
+ const customElement = new custom_element_1.CustomElement(base64ImageString, 'Dummy_element', 0.9, 10, 'RGB', [{ x: 0, y: 1 }, { x: 1, y: 2 }]);
43
+ customElement.validate();
44
+ }).toThrow('mask must contain at least 3 points');
45
+ });
46
+ test('should throw ValidationError if mask and threshold are both invalid', () => {
47
+ expect(() => {
48
+ const customElement = new custom_element_1.CustomElement(base64ImageString, 'Dummy_element', 90, 10, 'RGB', [{ x: 0, y: 1 }, { x: 1, y: 2 }]);
49
+ customElement.validate();
50
+ }).toThrow('threshold must be less than or equal to 1, mask must contain at least 3 points');
51
+ });
52
+ });
53
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const dsl_1 = require("./dsl");
13
+ class TestCommand extends dsl_1.FluentCommand {
14
+ // eslint-disable-next-line class-methods-use-this
15
+ fluentCommandExecutor(instruction, customElements) {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ // eslint-disable-next-line no-console
18
+ console.log(`${instruction} ${customElements}`);
19
+ return Promise.resolve();
20
+ });
21
+ }
22
+ }
23
+ describe('DSL', () => {
24
+ describe('custom element', () => {
25
+ test('should call exec function with zero custom element', () => __awaiter(void 0, void 0, void 0, function* () {
26
+ const underTest = new TestCommand();
27
+ const testCommandSpy = jest.spyOn(underTest, 'fluentCommandExecutor');
28
+ yield underTest.click().button()
29
+ .exec();
30
+ expect(testCommandSpy).toHaveBeenCalledWith('Click on button', []);
31
+ }));
32
+ test('should call exec function with one custom element', () => __awaiter(void 0, void 0, void 0, function* () {
33
+ const underTest = new TestCommand();
34
+ const testCommandSpy = jest.spyOn(underTest, 'fluentCommandExecutor');
35
+ yield underTest.click().customElement({
36
+ customImage: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
37
+ imageCompareFormat: 'grayscale',
38
+ name: 'custom element 1',
39
+ }).button()
40
+ .exec();
41
+ expect(testCommandSpy).toHaveBeenCalledWith('Click on custom element button', [{
42
+ customImage: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
43
+ imageCompareFormat: 'grayscale',
44
+ name: 'custom element 1',
45
+ }]);
46
+ }));
47
+ test('should call exec function with two custom element', () => __awaiter(void 0, void 0, void 0, function* () {
48
+ const underTest = new TestCommand();
49
+ const testCommandSpy = jest.spyOn(underTest, 'fluentCommandExecutor');
50
+ yield underTest.click().customElement({
51
+ customImage: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
52
+ imageCompareFormat: 'grayscale',
53
+ name: 'custom element 1',
54
+ })
55
+ .button()
56
+ .customElement({
57
+ customImage: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
58
+ imageCompareFormat: 'grayscale',
59
+ name: 'custom element 2',
60
+ })
61
+ .exec();
62
+ expect(testCommandSpy).toHaveBeenCalledWith('Click on custom element button custom element', [{
63
+ customImage: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
64
+ imageCompareFormat: 'grayscale',
65
+ name: 'custom element 1',
66
+ },
67
+ {
68
+ customImage: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
69
+ imageCompareFormat: 'grayscale',
70
+ name: 'custom element 2',
71
+ },
72
+ ]);
73
+ }));
74
+ });
75
+ });
@@ -14,6 +14,7 @@ export declare class InferenceClient {
14
14
  isImageRequired(instruction: string): Promise<boolean>;
15
15
  private resizeIfNeeded;
16
16
  inference(customElements?: CustomElement[], image?: string, instruction?: string): Promise<ControlCommand | Annotation>;
17
+ private static logMetaInformation;
17
18
  predictControlCommand(instruction: string, customElements?: CustomElement[], image?: string): Promise<ControlCommand>;
18
19
  getDetectedElements(instruction: string, image: string, customElements?: CustomElement[]): Promise<DetectedElement[]>;
19
20
  predictImageAnnotation(image: string, customElements?: CustomElement[]): Promise<Annotation>;
@@ -19,6 +19,7 @@ const annotation_1 = require("../core/annotation/annotation");
19
19
  const transformations_1 = require("../utils/transformations");
20
20
  const inference_response_error_1 = require("./inference-response-error");
21
21
  const config_error_1 = require("./config-error");
22
+ const logger_1 = require("../lib/logger");
22
23
  class InferenceClient {
23
24
  constructor(baseUrl, httpClient, resize, workspaceId, apiVersion = 'v3') {
24
25
  this.baseUrl = baseUrl;
@@ -27,7 +28,9 @@ class InferenceClient {
27
28
  this.workspaceId = workspaceId;
28
29
  this.apiVersion = apiVersion;
29
30
  const versionedBaseUrl = (0, url_join_1.default)(this.baseUrl, 'api', this.apiVersion);
30
- this.url = workspaceId ? (0, url_join_1.default)(versionedBaseUrl, 'workspaces', workspaceId) : versionedBaseUrl;
31
+ this.url = workspaceId
32
+ ? (0, url_join_1.default)(versionedBaseUrl, 'workspaces', workspaceId)
33
+ : versionedBaseUrl;
31
34
  if (this.resize !== undefined && this.resize <= 0) {
32
35
  throw new config_error_1.ConfigurationError(`Resize must be a positive number. The current resize value "${this.resize}" is not valid.`);
33
36
  }
@@ -36,17 +39,17 @@ class InferenceClient {
36
39
  isImageRequired(instruction) {
37
40
  return __awaiter(this, void 0, void 0, function* () {
38
41
  const url = (0, url_join_1.default)(this.url, 'instruction', 'is-image-required');
39
- const httpBody = {
42
+ const requestBody = {
40
43
  instruction,
41
44
  };
42
- const httpResponse = yield this.httpClient.post(url, httpBody);
43
- return httpResponse.isImageRequired;
45
+ const response = yield this.httpClient.post(url, requestBody);
46
+ return response.body.isImageRequired;
44
47
  });
45
48
  }
46
49
  // eslint-disable-next-line class-methods-use-this
47
50
  resizeIfNeeded(customElements, image) {
48
51
  return __awaiter(this, void 0, void 0, function* () {
49
- if (!(image) || customElements.length > 0 || this.resize === undefined) {
52
+ if (!image || customElements.length > 0 || this.resize === undefined) {
50
53
  return { base64Image: image, resizeRatio: 1 };
51
54
  }
52
55
  return (0, transformations_1.resizeBase64ImageWithSameRatio)(image, this.resize);
@@ -55,16 +58,22 @@ class InferenceClient {
55
58
  inference(customElements = [], image, instruction) {
56
59
  return __awaiter(this, void 0, void 0, function* () {
57
60
  const resizedImage = yield this.resizeIfNeeded(customElements, image);
58
- const httpBody = {
61
+ const requestBody = {
59
62
  image: resizedImage.base64Image,
60
63
  instruction,
61
64
  customElements,
62
65
  };
63
66
  const url = (0, url_join_1.default)(this.url, 'inference');
64
- const httpResponse = yield this.httpClient.post(url, httpBody);
65
- return ui_control_commands_1.InferenceResponse.fromJson(httpResponse, resizedImage.resizeRatio, image);
67
+ const response = yield this.httpClient.post(url, requestBody);
68
+ InferenceClient.logMetaInformation(response);
69
+ return ui_control_commands_1.InferenceResponse.fromJson(response.body, resizedImage.resizeRatio, image);
66
70
  });
67
71
  }
72
+ static logMetaInformation(response) {
73
+ if (response.headers['askui-usage-warnings'] !== undefined) {
74
+ logger_1.logger.warn(response.headers['askui-usage-warnings']);
75
+ }
76
+ }
68
77
  predictControlCommand(instruction, customElements = [], image) {
69
78
  return __awaiter(this, void 0, void 0, function* () {
70
79
  const inferenceResponse = yield this.inference(customElements, image, instruction);
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const read_environment_credentials_1 = require("./read-environment-credentials");
4
+ describe('envCredentials()', () => {
5
+ test('should read the credentials from the environment variables', () => {
6
+ process.env['ASKUI_TOKEN'] = 'token';
7
+ process.env['ASKUI_WORKSPACE_ID'] = 'id123';
8
+ const credentialsFromTheEnv = (0, read_environment_credentials_1.envCredentials)();
9
+ expect(credentialsFromTheEnv).toStrictEqual({ workspaceId: 'id123', token: 'token' });
10
+ });
11
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ui_controller_args_1 = require("./ui-controller-args");
4
+ describe('createCliFlagsFromArgs()', () => {
5
+ test('test createCliFlagsFromArgs should return -d 0 as default output', () => {
6
+ const expected = ['-d 0', '-p 6769', '--action_wait_time 1000', '--host 127.0.0.1', '-m ', '--log-level debug'];
7
+ const argsWithDefaults = (0, ui_controller_args_1.createArgsWithDefaults)();
8
+ const actual = (0, ui_controller_args_1.createCliFlagsFromArgs)(argsWithDefaults);
9
+ expect(actual).toStrictEqual(expected);
10
+ });
11
+ test('test createCliFlagsFromArgs output should include -d 0 when no display was selected', () => {
12
+ const expected = ['-d 0', '-p 6777', '--action_wait_time 1000', '--host 0.0.0.0', '-m ', '--log-level debug'];
13
+ const argsWithDefaults = (0, ui_controller_args_1.createArgsWithDefaults)({ port: 6777, host: '0.0.0.0' });
14
+ const actual = (0, ui_controller_args_1.createCliFlagsFromArgs)(argsWithDefaults);
15
+ expect(actual).toStrictEqual(expected);
16
+ });
17
+ test('test createCliFlagsFromArgs output should include the display that was selected ', () => {
18
+ const expected = ['-d 99', '-p 6777', '--action_wait_time 1000', '--host 0.0.0.0', '-m ', '--log-level debug'];
19
+ const argsWithDefaults = (0, ui_controller_args_1.createArgsWithDefaults)({ port: 6777, host: '0.0.0.0', display: 99 });
20
+ const actual = (0, ui_controller_args_1.createCliFlagsFromArgs)(argsWithDefaults);
21
+ expect(actual).toStrictEqual(expected);
22
+ });
23
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const credentials_1 = require("./credentials");
4
+ describe('Credentials', () => {
5
+ describe('base64Encoded()', () => {
6
+ test('should return base64-encoded credentials', () => {
7
+ const credentials = new credentials_1.Credentials('password');
8
+ expect(credentials.base64Encoded).toBe('cGFzc3dvcmQ=');
9
+ });
10
+ });
11
+ });
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import { OptionsOfJSONResponseBody } from 'got';
2
3
  import http from 'http';
3
4
  import https from 'https';
@@ -17,6 +18,9 @@ export declare class HttpClientGot {
17
18
  } | undefined);
18
19
  private initHeaders;
19
20
  private injectHeadersAndCookies;
20
- post<T>(url: string, data: Record<string | number | symbol, unknown>): Promise<T>;
21
+ post<T>(url: string, data: Record<string | number | symbol, unknown>): Promise<{
22
+ headers: http.IncomingHttpHeaders;
23
+ body: T;
24
+ }>;
21
25
  get<T>(url: string, options?: OptionsOfJSONResponseBody): Promise<T>;
22
26
  }
@@ -30,18 +30,26 @@ class HttpClientGot {
30
30
  }
31
31
  initHeaders(token, customHeaders = {}) {
32
32
  const credentials = token ? new credentials_1.Credentials(token) : undefined;
33
- this.headers = Object.assign(Object.assign({}, (credentials ? { Authorization: `Basic ${credentials === null || credentials === void 0 ? void 0 : credentials.base64Encoded}` } : {})), customHeaders);
33
+ this.headers = Object.assign(Object.assign({}, (credentials
34
+ ? { Authorization: `Basic ${credentials === null || credentials === void 0 ? void 0 : credentials.base64Encoded}` }
35
+ : {})), customHeaders);
34
36
  }
35
37
  injectHeadersAndCookies(url, options) {
36
38
  const cookieJar = new tough_cookie_1.CookieJar();
37
- Object.keys(this.cookies).map((key) => `${key}=${this.cookies[key]}`).forEach((cookie) => {
39
+ Object.keys(this.cookies)
40
+ .map((key) => `${key}=${this.cookies[key]}`)
41
+ .forEach((cookie) => {
38
42
  cookieJar.setCookieSync(cookie, url);
39
43
  });
40
44
  return Object.assign(Object.assign({}, options), { headers: this.headers, cookieJar });
41
45
  }
42
46
  post(url, data) {
43
47
  return __awaiter(this, void 0, void 0, function* () {
44
- const options = this.injectHeadersAndCookies(url, { json: data, responseType: 'json', throwHttpErrors: false });
48
+ const options = this.injectHeadersAndCookies(url, {
49
+ json: data,
50
+ responseType: 'json',
51
+ throwHttpErrors: false,
52
+ });
45
53
  const { body, statusCode, headers } = yield this.askuiGot.post(url, options);
46
54
  if (headers['deprecation'] !== undefined) {
47
55
  lib_1.logger.warn(headers['deprecation']);
@@ -49,7 +57,7 @@ class HttpClientGot {
49
57
  if (statusCode !== 200) {
50
58
  throw (0, custom_errors_1.httpClientErrorHandler)(statusCode, JSON.stringify(body));
51
59
  }
52
- return body;
60
+ return { headers, body };
53
61
  });
54
62
  }
55
63
  get(url, options = { responseType: 'json' }) {
@@ -0,0 +1,5 @@
1
+ import { DetectedElement } from '../model/annotation-result/detected-element';
2
+ export interface AnnotationJson {
3
+ image: string;
4
+ objects: DetectedElement[];
5
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,15 +1,11 @@
1
1
  import { ControlCommand } from '../ui-control-commands/control-command';
2
2
  import { Annotation } from '../annotation/annotation';
3
- export declare class InferenceResponse {
4
- type: string;
5
- data: ControlCommand | Annotation;
6
- constructor(type: string, data: ControlCommand | Annotation);
7
- static fromJson(json: unknown, resizeRatio?: number, image?: string): ControlCommand | Annotation;
8
- static createModels(type: string, data: ControlCommand | Annotation, resizeRatio: number, image?: string): ControlCommand | Annotation;
9
- static models: Models;
3
+ import { ModelType } from './model-type';
4
+ export interface InferenceResponseBody {
5
+ type: ModelType;
6
+ data: ModelType extends 'COMMANDS' ? ControlCommand : Annotation;
10
7
  }
11
- interface Models {
12
- DETECTED_ELEMENTS: CallableFunction;
13
- COMMANDS: CallableFunction;
8
+ export declare class InferenceResponse {
9
+ static fromJson(json: InferenceResponseBody, resizeRatio?: number, image?: string): ControlCommand | Annotation;
10
+ static createModels(type: ModelType, data: ModelType extends 'COMMANDS' ? ControlCommand : Annotation, resizeRatio: number, image?: string): ControlCommand | Annotation;
14
11
  }
15
- export {};
@@ -1,21 +1,16 @@
1
1
  import { ControlCommand } from '../ui-control-commands/control-command';
2
2
  import { Annotation } from '../annotation/annotation';
3
+ import { InvalidModelTypeError } from './invalid-model-type-error';
3
4
  export class InferenceResponse {
4
- constructor(type, data) {
5
- this.type = type;
6
- this.data = data;
7
- }
8
5
  static fromJson(json, resizeRatio = 1, image) {
9
- const inferenceResponse = json;
10
- return this.createModels(inferenceResponse.type, inferenceResponse.data, resizeRatio, image);
6
+ return this.createModels(json.type, json.data, resizeRatio, image);
11
7
  }
12
8
  static createModels(type, data, resizeRatio, image) {
13
- return this.models[type](data, resizeRatio, image);
9
+ if (type === 'COMMANDS')
10
+ return ControlCommand.fromJson(data, resizeRatio);
11
+ if (type === 'DETECTED_ELEMENTS') {
12
+ return Annotation.fromJson({ image, detected_elements: data.detected_elements }, resizeRatio);
13
+ }
14
+ throw new InvalidModelTypeError(type);
14
15
  }
15
16
  }
16
- InferenceResponse.models = {
17
- DETECTED_ELEMENTS: (data, resizeRatio, image) => Annotation
18
- .fromJson({ image, detected_elements: data.detected_elements }, resizeRatio),
19
- COMMANDS: (data, resizeRatio) => ControlCommand
20
- .fromJson(data, resizeRatio),
21
- };
@@ -0,0 +1,4 @@
1
+ import { ModelType } from './model-type';
2
+ export declare class InvalidModelTypeError extends Error {
3
+ constructor(type: ModelType);
4
+ }
@@ -0,0 +1,5 @@
1
+ export class InvalidModelTypeError extends Error {
2
+ constructor(type) {
3
+ super(`Invalid model type: ${type}`);
4
+ }
5
+ }
@@ -0,0 +1 @@
1
+ export declare type ModelType = 'DETECTED_ELEMENTS' | 'COMMANDS';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,51 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { CustomElement } from './custom-element';
11
+ const base64ImageString = 'data:image/png;base64,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';
12
+ describe('CustomElement', () => {
13
+ describe('fromJsonWithImagePathOrImage', () => {
14
+ test('should return CustomElement if CustomElement created from JSON is valid', () => __awaiter(void 0, void 0, void 0, function* () {
15
+ const expected = new CustomElement(base64ImageString, 'Dummy_element', 0.7, 10, 'RGB', [{ x: 0, y: 1 }, { x: 1, y: 2 }, { x: 3, y: 4 }]);
16
+ const actual = yield CustomElement.fromJsonWithImagePathOrImage({
17
+ customImage: base64ImageString,
18
+ name: 'Dummy_element',
19
+ threshold: 0.7,
20
+ rotationDegreePerStep: 10,
21
+ imageCompareFormat: 'RGB',
22
+ mask: [{ x: 0, y: 1 }, { x: 1, y: 2 }, { x: 3, y: 4 }],
23
+ });
24
+ expect(actual).toStrictEqual(expected);
25
+ }));
26
+ test('should throw ValidationError if threshold is invalid', () => {
27
+ expect(() => {
28
+ const customElement = new CustomElement(base64ImageString, 'Dummy_element', 1.1, 10, 'RGB', [{ x: 0, y: 1 }, { x: 1, y: 2 }, { x: 3, y: 4 }]);
29
+ customElement.validate();
30
+ }).toThrow('threshold must be less than or equal to 1');
31
+ });
32
+ test('should throw ValidationError if rotationDegreePerStep is invalid', () => {
33
+ expect(() => {
34
+ const customElement = new CustomElement(base64ImageString, 'Dummy_element', 0.9, -90, 'RGB', [{ x: 0, y: 1 }, { x: 1, y: 2 }, { x: 3, y: 4 }]);
35
+ customElement.validate();
36
+ }).toThrow('rotationDegreePerStep must be greater than or equal to 0');
37
+ });
38
+ test('should throw ValidationError if mask is invalid', () => {
39
+ expect(() => {
40
+ const customElement = new CustomElement(base64ImageString, 'Dummy_element', 0.9, 10, 'RGB', [{ x: 0, y: 1 }, { x: 1, y: 2 }]);
41
+ customElement.validate();
42
+ }).toThrow('mask must contain at least 3 points');
43
+ });
44
+ test('should throw ValidationError if mask and threshold are both invalid', () => {
45
+ expect(() => {
46
+ const customElement = new CustomElement(base64ImageString, 'Dummy_element', 90, 10, 'RGB', [{ x: 0, y: 1 }, { x: 1, y: 2 }]);
47
+ customElement.validate();
48
+ }).toThrow('threshold must be less than or equal to 1, mask must contain at least 3 points');
49
+ });
50
+ });
51
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,73 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { FluentCommand } from './dsl';
11
+ class TestCommand extends FluentCommand {
12
+ // eslint-disable-next-line class-methods-use-this
13
+ fluentCommandExecutor(instruction, customElements) {
14
+ return __awaiter(this, void 0, void 0, function* () {
15
+ // eslint-disable-next-line no-console
16
+ console.log(`${instruction} ${customElements}`);
17
+ return Promise.resolve();
18
+ });
19
+ }
20
+ }
21
+ describe('DSL', () => {
22
+ describe('custom element', () => {
23
+ test('should call exec function with zero custom element', () => __awaiter(void 0, void 0, void 0, function* () {
24
+ const underTest = new TestCommand();
25
+ const testCommandSpy = jest.spyOn(underTest, 'fluentCommandExecutor');
26
+ yield underTest.click().button()
27
+ .exec();
28
+ expect(testCommandSpy).toHaveBeenCalledWith('Click on button', []);
29
+ }));
30
+ test('should call exec function with one custom element', () => __awaiter(void 0, void 0, void 0, function* () {
31
+ const underTest = new TestCommand();
32
+ const testCommandSpy = jest.spyOn(underTest, 'fluentCommandExecutor');
33
+ yield underTest.click().customElement({
34
+ customImage: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
35
+ imageCompareFormat: 'grayscale',
36
+ name: 'custom element 1',
37
+ }).button()
38
+ .exec();
39
+ expect(testCommandSpy).toHaveBeenCalledWith('Click on custom element button', [{
40
+ customImage: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
41
+ imageCompareFormat: 'grayscale',
42
+ name: 'custom element 1',
43
+ }]);
44
+ }));
45
+ test('should call exec function with two custom element', () => __awaiter(void 0, void 0, void 0, function* () {
46
+ const underTest = new TestCommand();
47
+ const testCommandSpy = jest.spyOn(underTest, 'fluentCommandExecutor');
48
+ yield underTest.click().customElement({
49
+ customImage: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
50
+ imageCompareFormat: 'grayscale',
51
+ name: 'custom element 1',
52
+ })
53
+ .button()
54
+ .customElement({
55
+ customImage: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
56
+ imageCompareFormat: 'grayscale',
57
+ name: 'custom element 2',
58
+ })
59
+ .exec();
60
+ expect(testCommandSpy).toHaveBeenCalledWith('Click on custom element button custom element', [{
61
+ customImage: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
62
+ imageCompareFormat: 'grayscale',
63
+ name: 'custom element 1',
64
+ },
65
+ {
66
+ customImage: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
67
+ imageCompareFormat: 'grayscale',
68
+ name: 'custom element 2',
69
+ },
70
+ ]);
71
+ }));
72
+ });
73
+ });
@@ -14,6 +14,7 @@ export declare class InferenceClient {
14
14
  isImageRequired(instruction: string): Promise<boolean>;
15
15
  private resizeIfNeeded;
16
16
  inference(customElements?: CustomElement[], image?: string, instruction?: string): Promise<ControlCommand | Annotation>;
17
+ private static logMetaInformation;
17
18
  predictControlCommand(instruction: string, customElements?: CustomElement[], image?: string): Promise<ControlCommand>;
18
19
  getDetectedElements(instruction: string, image: string, customElements?: CustomElement[]): Promise<DetectedElement[]>;
19
20
  predictImageAnnotation(image: string, customElements?: CustomElement[]): Promise<Annotation>;
@@ -13,6 +13,7 @@ import { Annotation } from '../core/annotation/annotation';
13
13
  import { resizeBase64ImageWithSameRatio } from '../utils/transformations';
14
14
  import { InferenceResponseError } from './inference-response-error';
15
15
  import { ConfigurationError } from './config-error';
16
+ import { logger } from '../lib/logger';
16
17
  export class InferenceClient {
17
18
  constructor(baseUrl, httpClient, resize, workspaceId, apiVersion = 'v3') {
18
19
  this.baseUrl = baseUrl;
@@ -21,7 +22,9 @@ export class InferenceClient {
21
22
  this.workspaceId = workspaceId;
22
23
  this.apiVersion = apiVersion;
23
24
  const versionedBaseUrl = urljoin(this.baseUrl, 'api', this.apiVersion);
24
- this.url = workspaceId ? urljoin(versionedBaseUrl, 'workspaces', workspaceId) : versionedBaseUrl;
25
+ this.url = workspaceId
26
+ ? urljoin(versionedBaseUrl, 'workspaces', workspaceId)
27
+ : versionedBaseUrl;
25
28
  if (this.resize !== undefined && this.resize <= 0) {
26
29
  throw new ConfigurationError(`Resize must be a positive number. The current resize value "${this.resize}" is not valid.`);
27
30
  }
@@ -30,17 +33,17 @@ export class InferenceClient {
30
33
  isImageRequired(instruction) {
31
34
  return __awaiter(this, void 0, void 0, function* () {
32
35
  const url = urljoin(this.url, 'instruction', 'is-image-required');
33
- const httpBody = {
36
+ const requestBody = {
34
37
  instruction,
35
38
  };
36
- const httpResponse = yield this.httpClient.post(url, httpBody);
37
- return httpResponse.isImageRequired;
39
+ const response = yield this.httpClient.post(url, requestBody);
40
+ return response.body.isImageRequired;
38
41
  });
39
42
  }
40
43
  // eslint-disable-next-line class-methods-use-this
41
44
  resizeIfNeeded(customElements, image) {
42
45
  return __awaiter(this, void 0, void 0, function* () {
43
- if (!(image) || customElements.length > 0 || this.resize === undefined) {
46
+ if (!image || customElements.length > 0 || this.resize === undefined) {
44
47
  return { base64Image: image, resizeRatio: 1 };
45
48
  }
46
49
  return resizeBase64ImageWithSameRatio(image, this.resize);
@@ -49,16 +52,22 @@ export class InferenceClient {
49
52
  inference(customElements = [], image, instruction) {
50
53
  return __awaiter(this, void 0, void 0, function* () {
51
54
  const resizedImage = yield this.resizeIfNeeded(customElements, image);
52
- const httpBody = {
55
+ const requestBody = {
53
56
  image: resizedImage.base64Image,
54
57
  instruction,
55
58
  customElements,
56
59
  };
57
60
  const url = urljoin(this.url, 'inference');
58
- const httpResponse = yield this.httpClient.post(url, httpBody);
59
- return InferenceResponse.fromJson(httpResponse, resizedImage.resizeRatio, image);
61
+ const response = yield this.httpClient.post(url, requestBody);
62
+ InferenceClient.logMetaInformation(response);
63
+ return InferenceResponse.fromJson(response.body, resizedImage.resizeRatio, image);
60
64
  });
61
65
  }
66
+ static logMetaInformation(response) {
67
+ if (response.headers['askui-usage-warnings'] !== undefined) {
68
+ logger.warn(response.headers['askui-usage-warnings']);
69
+ }
70
+ }
62
71
  predictControlCommand(instruction, customElements = [], image) {
63
72
  return __awaiter(this, void 0, void 0, function* () {
64
73
  const inferenceResponse = yield this.inference(customElements, image, instruction);
@@ -0,0 +1,9 @@
1
+ import { envCredentials } from './read-environment-credentials';
2
+ describe('envCredentials()', () => {
3
+ test('should read the credentials from the environment variables', () => {
4
+ process.env['ASKUI_TOKEN'] = 'token';
5
+ process.env['ASKUI_WORKSPACE_ID'] = 'id123';
6
+ const credentialsFromTheEnv = envCredentials();
7
+ expect(credentialsFromTheEnv).toStrictEqual({ workspaceId: 'id123', token: 'token' });
8
+ });
9
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,21 @@
1
+ import { createArgsWithDefaults, createCliFlagsFromArgs } from './ui-controller-args';
2
+ describe('createCliFlagsFromArgs()', () => {
3
+ test('test createCliFlagsFromArgs should return -d 0 as default output', () => {
4
+ const expected = ['-d 0', '-p 6769', '--action_wait_time 1000', '--host 127.0.0.1', '-m ', '--log-level debug'];
5
+ const argsWithDefaults = createArgsWithDefaults();
6
+ const actual = createCliFlagsFromArgs(argsWithDefaults);
7
+ expect(actual).toStrictEqual(expected);
8
+ });
9
+ test('test createCliFlagsFromArgs output should include -d 0 when no display was selected', () => {
10
+ const expected = ['-d 0', '-p 6777', '--action_wait_time 1000', '--host 0.0.0.0', '-m ', '--log-level debug'];
11
+ const argsWithDefaults = createArgsWithDefaults({ port: 6777, host: '0.0.0.0' });
12
+ const actual = createCliFlagsFromArgs(argsWithDefaults);
13
+ expect(actual).toStrictEqual(expected);
14
+ });
15
+ test('test createCliFlagsFromArgs output should include the display that was selected ', () => {
16
+ const expected = ['-d 99', '-p 6777', '--action_wait_time 1000', '--host 0.0.0.0', '-m ', '--log-level debug'];
17
+ const argsWithDefaults = createArgsWithDefaults({ port: 6777, host: '0.0.0.0', display: 99 });
18
+ const actual = createCliFlagsFromArgs(argsWithDefaults);
19
+ expect(actual).toStrictEqual(expected);
20
+ });
21
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import { Credentials } from './credentials';
2
+ describe('Credentials', () => {
3
+ describe('base64Encoded()', () => {
4
+ test('should return base64-encoded credentials', () => {
5
+ const credentials = new Credentials('password');
6
+ expect(credentials.base64Encoded).toBe('cGFzc3dvcmQ=');
7
+ });
8
+ });
9
+ });
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import { OptionsOfJSONResponseBody } from 'got';
2
3
  import http from 'http';
3
4
  import https from 'https';
@@ -17,6 +18,9 @@ export declare class HttpClientGot {
17
18
  } | undefined);
18
19
  private initHeaders;
19
20
  private injectHeadersAndCookies;
20
- post<T>(url: string, data: Record<string | number | symbol, unknown>): Promise<T>;
21
+ post<T>(url: string, data: Record<string | number | symbol, unknown>): Promise<{
22
+ headers: http.IncomingHttpHeaders;
23
+ body: T;
24
+ }>;
21
25
  get<T>(url: string, options?: OptionsOfJSONResponseBody): Promise<T>;
22
26
  }
@@ -24,18 +24,26 @@ export class HttpClientGot {
24
24
  }
25
25
  initHeaders(token, customHeaders = {}) {
26
26
  const credentials = token ? new Credentials(token) : undefined;
27
- this.headers = Object.assign(Object.assign({}, (credentials ? { Authorization: `Basic ${credentials === null || credentials === void 0 ? void 0 : credentials.base64Encoded}` } : {})), customHeaders);
27
+ this.headers = Object.assign(Object.assign({}, (credentials
28
+ ? { Authorization: `Basic ${credentials === null || credentials === void 0 ? void 0 : credentials.base64Encoded}` }
29
+ : {})), customHeaders);
28
30
  }
29
31
  injectHeadersAndCookies(url, options) {
30
32
  const cookieJar = new CookieJar();
31
- Object.keys(this.cookies).map((key) => `${key}=${this.cookies[key]}`).forEach((cookie) => {
33
+ Object.keys(this.cookies)
34
+ .map((key) => `${key}=${this.cookies[key]}`)
35
+ .forEach((cookie) => {
32
36
  cookieJar.setCookieSync(cookie, url);
33
37
  });
34
38
  return Object.assign(Object.assign({}, options), { headers: this.headers, cookieJar });
35
39
  }
36
40
  post(url, data) {
37
41
  return __awaiter(this, void 0, void 0, function* () {
38
- const options = this.injectHeadersAndCookies(url, { json: data, responseType: 'json', throwHttpErrors: false });
42
+ const options = this.injectHeadersAndCookies(url, {
43
+ json: data,
44
+ responseType: 'json',
45
+ throwHttpErrors: false,
46
+ });
39
47
  const { body, statusCode, headers } = yield this.askuiGot.post(url, options);
40
48
  if (headers['deprecation'] !== undefined) {
41
49
  logger.warn(headers['deprecation']);
@@ -43,7 +51,7 @@ export class HttpClientGot {
43
51
  if (statusCode !== 200) {
44
52
  throw httpClientErrorHandler(statusCode, JSON.stringify(body));
45
53
  }
46
- return body;
54
+ return { headers, body };
47
55
  });
48
56
  }
49
57
  get(url, options = { responseType: 'json' }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "askui",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "license": "MIT",
5
5
  "author": "askui GmbH <info@askui.com> (http://www.askui.com/)",
6
6
  "description": "Reliable, automated end-to-end-testing that depends on what is shown on your screen instead of the technology you are running on",