@aspiresys/visor 1.2.7 → 1.2.9
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/dist/index.d.ts +16 -4
- package/dist/index.js +20 -8
- package/dist/mouse.d.ts +8 -2
- package/dist/mouse.js +11 -5
- package/dist/types.d.ts +4 -0
- package/inspector/index.html +20 -73
- package/inspector/src/renderer.js +12 -15
- package/inspector/styles.css +67 -30
- package/inspector/templates/template.png +0 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -36,7 +36,10 @@ export declare class Visor {
|
|
|
36
36
|
* @example
|
|
37
37
|
* await visor.click("./images/save.png", 0.9);
|
|
38
38
|
*/
|
|
39
|
-
click(image?: string, confidence?: number
|
|
39
|
+
click(image?: string, confidence?: number, offset?: {
|
|
40
|
+
x: number;
|
|
41
|
+
y: number;
|
|
42
|
+
}): Promise<void>;
|
|
40
43
|
/**
|
|
41
44
|
* Performs a right mouse click.
|
|
42
45
|
*
|
|
@@ -61,7 +64,10 @@ export declare class Visor {
|
|
|
61
64
|
* @example
|
|
62
65
|
* await visor.rightClick();
|
|
63
66
|
*/
|
|
64
|
-
rightClick(image?: string, confidence?: number
|
|
67
|
+
rightClick(image?: string, confidence?: number, offset?: {
|
|
68
|
+
x: number;
|
|
69
|
+
y: number;
|
|
70
|
+
}): Promise<void>;
|
|
65
71
|
/**
|
|
66
72
|
* Performs a double left mouse click.
|
|
67
73
|
*
|
|
@@ -87,7 +93,10 @@ export declare class Visor {
|
|
|
87
93
|
* @example
|
|
88
94
|
* await visor.doubleClick();
|
|
89
95
|
*/
|
|
90
|
-
doubleClick(image?: string, confidence?: number
|
|
96
|
+
doubleClick(image?: string, confidence?: number, offset?: {
|
|
97
|
+
x: number;
|
|
98
|
+
y: number;
|
|
99
|
+
}): Promise<void>;
|
|
91
100
|
/**
|
|
92
101
|
* Finds the best matching image on screen
|
|
93
102
|
* using OpenCV template matching.
|
|
@@ -495,7 +504,10 @@ export declare class Visor {
|
|
|
495
504
|
* @example
|
|
496
505
|
* await visor.hover("menu.png");
|
|
497
506
|
*/
|
|
498
|
-
hover(image
|
|
507
|
+
hover(image?: string, confidence?: number, offset?: {
|
|
508
|
+
x: number;
|
|
509
|
+
y: number;
|
|
510
|
+
}): Promise<void>;
|
|
499
511
|
/**
|
|
500
512
|
* Scrolls the mouse wheel downward.
|
|
501
513
|
*
|
package/dist/index.js
CHANGED
|
@@ -78,7 +78,10 @@ class Visor {
|
|
|
78
78
|
* @example
|
|
79
79
|
* await visor.click("./images/save.png", 0.9);
|
|
80
80
|
*/
|
|
81
|
-
async click(image, confidence = 0.8
|
|
81
|
+
async click(image, confidence = 0.8, offset = {
|
|
82
|
+
x: 0,
|
|
83
|
+
y: 0
|
|
84
|
+
}) {
|
|
82
85
|
this.checkConfig();
|
|
83
86
|
if (!image) {
|
|
84
87
|
await this.mouse.click(this.Button.LEFT);
|
|
@@ -90,7 +93,7 @@ class Visor {
|
|
|
90
93
|
throw new Error(`Image not found: ${image}`);
|
|
91
94
|
}
|
|
92
95
|
(0, logger_1.log)("[CV] Match found:", region);
|
|
93
|
-
await (0, mouse_1.clickRegion)(region);
|
|
96
|
+
await (0, mouse_1.clickRegion)(region, offset);
|
|
94
97
|
}
|
|
95
98
|
/**
|
|
96
99
|
* Performs a right mouse click.
|
|
@@ -116,14 +119,17 @@ class Visor {
|
|
|
116
119
|
* @example
|
|
117
120
|
* await visor.rightClick();
|
|
118
121
|
*/
|
|
119
|
-
async rightClick(image, confidence = 0.8
|
|
122
|
+
async rightClick(image, confidence = 0.8, offset = {
|
|
123
|
+
x: 0,
|
|
124
|
+
y: 0
|
|
125
|
+
}) {
|
|
120
126
|
this.checkConfig();
|
|
121
127
|
if (image) {
|
|
122
128
|
const region = await this.find(image, confidence);
|
|
123
129
|
if (!region) {
|
|
124
130
|
throw new Error(`Image not found: ${image}`);
|
|
125
131
|
}
|
|
126
|
-
await (0, mouse_1.moveToRegion)(region);
|
|
132
|
+
await (0, mouse_1.moveToRegion)(region, offset);
|
|
127
133
|
}
|
|
128
134
|
await this.mouse.click(this.Button.RIGHT);
|
|
129
135
|
(0, logger_1.log)("[MOUSE] Right click completed");
|
|
@@ -153,14 +159,17 @@ class Visor {
|
|
|
153
159
|
* @example
|
|
154
160
|
* await visor.doubleClick();
|
|
155
161
|
*/
|
|
156
|
-
async doubleClick(image, confidence = 0.8
|
|
162
|
+
async doubleClick(image, confidence = 0.8, offset = {
|
|
163
|
+
x: 0,
|
|
164
|
+
y: 0
|
|
165
|
+
}) {
|
|
157
166
|
this.checkConfig();
|
|
158
167
|
if (image) {
|
|
159
168
|
const region = await this.find(image, confidence);
|
|
160
169
|
if (!region) {
|
|
161
170
|
throw new Error(`Image not found: ${image}`);
|
|
162
171
|
}
|
|
163
|
-
await (0, mouse_1.moveToRegion)(region);
|
|
172
|
+
await (0, mouse_1.moveToRegion)(region, offset);
|
|
164
173
|
}
|
|
165
174
|
await this.mouse.doubleClick(this.Button.LEFT);
|
|
166
175
|
(0, logger_1.log)("[MOUSE] Double click completed");
|
|
@@ -674,13 +683,16 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
674
683
|
* @example
|
|
675
684
|
* await visor.hover("menu.png");
|
|
676
685
|
*/
|
|
677
|
-
async hover(image, confidence = 0.8
|
|
686
|
+
async hover(image, confidence = 0.8, offset = {
|
|
687
|
+
x: 0,
|
|
688
|
+
y: 0
|
|
689
|
+
}) {
|
|
678
690
|
this.checkConfig();
|
|
679
691
|
const region = await this.find(image, confidence);
|
|
680
692
|
if (!region) {
|
|
681
693
|
throw new Error(`Image not found: ${image}`);
|
|
682
694
|
}
|
|
683
|
-
await (0, mouse_1.moveToRegion)(region);
|
|
695
|
+
await (0, mouse_1.moveToRegion)(region, offset);
|
|
684
696
|
(0, logger_1.log)("[MOUSE] Hover completed");
|
|
685
697
|
}
|
|
686
698
|
/**
|
package/dist/mouse.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
import { Region } from "./types";
|
|
2
|
-
export declare function moveToRegion(region: Region
|
|
3
|
-
|
|
2
|
+
export declare function moveToRegion(region: Region, offset?: {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
}): Promise<void>;
|
|
6
|
+
export declare function clickRegion(region: Region, offset?: {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
}): Promise<void>;
|
package/dist/mouse.js
CHANGED
|
@@ -5,15 +5,21 @@ exports.clickRegion = clickRegion;
|
|
|
5
5
|
const nut_js_1 = require("@nut-tree-fork/nut-js");
|
|
6
6
|
const config_1 = require("./config");
|
|
7
7
|
const logger_1 = require("./logger");
|
|
8
|
-
async function moveToRegion(region
|
|
8
|
+
async function moveToRegion(region, offset = {
|
|
9
|
+
x: 0,
|
|
10
|
+
y: 0
|
|
11
|
+
}) {
|
|
9
12
|
const scaleFactor = config_1.visorConfig.scaleFactor;
|
|
10
|
-
const centerX = Math.floor((region.x + region.width / 2) / scaleFactor);
|
|
11
|
-
const centerY = Math.floor((region.y + region.height / 2) / scaleFactor);
|
|
13
|
+
const centerX = Math.floor((region.x + region.width / 2 + offset.x) / scaleFactor);
|
|
14
|
+
const centerY = Math.floor((region.y + region.height / 2 + offset.y) / scaleFactor);
|
|
12
15
|
(0, logger_1.log)("[MOUSE] Moving mouse to:", centerX, centerY);
|
|
13
16
|
await nut_js_1.mouse.move([new nut_js_1.Point(centerX, centerY)]);
|
|
14
17
|
}
|
|
15
|
-
async function clickRegion(region
|
|
16
|
-
|
|
18
|
+
async function clickRegion(region, offset = {
|
|
19
|
+
x: 0,
|
|
20
|
+
y: 0
|
|
21
|
+
}) {
|
|
22
|
+
await moveToRegion(region, offset);
|
|
17
23
|
await new Promise((r) => setTimeout(r, 200));
|
|
18
24
|
await nut_js_1.mouse.click(nut_js_1.Button.LEFT);
|
|
19
25
|
(0, logger_1.log)("[MOUSE] Left click completed");
|
package/dist/types.d.ts
CHANGED
package/inspector/index.html
CHANGED
|
@@ -9,103 +9,50 @@
|
|
|
9
9
|
<header class="header">
|
|
10
10
|
<h3>VISOR INSPECTOR</h3>
|
|
11
11
|
</header>
|
|
12
|
-
|
|
13
12
|
<section class="controls-section">
|
|
14
13
|
<div class="toolbar">
|
|
15
14
|
<button id="captureBtn" class="btn btn-primary">
|
|
16
|
-
<span class="btn-icon">📸</span> Capture Screen
|
|
17
|
-
</button>
|
|
15
|
+
<span class="btn-icon">📸</span> Capture Screen </button>
|
|
18
16
|
<button id="saveBtn" class="btn btn-secondary">
|
|
19
|
-
<span class="btn-icon">💾</span> Save Template
|
|
20
|
-
</button>
|
|
17
|
+
<span class="btn-icon">💾</span> Save Template </button>
|
|
21
18
|
<button id="loadTemplateBtn" class="btn btn-secondary">
|
|
22
|
-
<span class="btn-icon">📂</span> Load Template
|
|
23
|
-
</button>
|
|
19
|
+
<span class="btn-icon">📂</span> Load Template </button>
|
|
24
20
|
<button id="testMatchBtn" class="btn btn-accent">
|
|
25
|
-
<span class="btn-icon">✓</span> Test Match
|
|
26
|
-
</button>
|
|
21
|
+
<span class="btn-icon">✓</span> Test Match </button>
|
|
27
22
|
<div class="controls-grid">
|
|
28
23
|
<div class="control-group">
|
|
29
24
|
<div class="input-wrapper">
|
|
30
25
|
<span class="input-hint">Confidence</span>
|
|
31
|
-
<input
|
|
32
|
-
id="confidenceInput"
|
|
33
|
-
type="number"
|
|
34
|
-
min="0"
|
|
35
|
-
max="1"
|
|
36
|
-
step="0.01"
|
|
37
|
-
value="0.8"
|
|
38
|
-
/>
|
|
26
|
+
<input id="confidenceInput" type="number" min="0" max="1" step="0.01" value="0.8" />
|
|
39
27
|
<span class="input-hint">(0.0 - 1.0)</span>
|
|
40
28
|
</div>
|
|
41
29
|
</div>
|
|
42
30
|
</div>
|
|
43
31
|
</div>
|
|
44
32
|
</section>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
33
|
+
<div class="capture-layout">
|
|
34
|
+
<div class="capture-panel">
|
|
35
|
+
<h3 class="section-title"> Current Capture </h3>
|
|
36
|
+
<canvas id="screenCanvas" class="canvas"></canvas>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="result-panel">
|
|
39
|
+
<h3 class="section-title"> Match Result </h3>
|
|
40
|
+
<div id="matchResult"> No Match Tested </div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
51
43
|
<section class="template-section">
|
|
52
44
|
<h3 class="section-title">Template Management</h3>
|
|
53
45
|
<div class="template-grid">
|
|
54
46
|
<div class="template-info">
|
|
55
|
-
<p
|
|
56
|
-
|
|
47
|
+
<p>
|
|
48
|
+
<strong>Current Template: </strong>
|
|
49
|
+
<span id="currentTemplate" class="template-status">None</span>
|
|
50
|
+
</p>
|
|
57
51
|
</div>
|
|
58
52
|
<img id="templatePreview" class="template-preview" />
|
|
59
53
|
</div>
|
|
60
|
-
|
|
61
|
-
<h3 class="section-title">
|
|
62
|
-
Match Result
|
|
63
|
-
</h3>
|
|
64
|
-
<div id="matchStatus"
|
|
65
|
-
class="match-status">
|
|
66
|
-
No Match Tested
|
|
67
|
-
</div>
|
|
68
|
-
<div class="match-details">
|
|
69
|
-
<div class="match-row">
|
|
70
|
-
<span class="match-label">
|
|
71
|
-
Confidence
|
|
72
|
-
</span>
|
|
73
|
-
<span id="resultConfidence"
|
|
74
|
-
class="match-value">
|
|
75
|
-
—
|
|
76
|
-
</span>
|
|
77
|
-
</div>
|
|
78
|
-
<div class="match-row">
|
|
79
|
-
<span class="match-label">
|
|
80
|
-
Position
|
|
81
|
-
</span>
|
|
82
|
-
<span class="match-value">
|
|
83
|
-
X:
|
|
84
|
-
<span id="resultX">—</span>
|
|
85
|
-
|
|
|
86
|
-
|
|
87
|
-
Y:
|
|
88
|
-
<span id="resultY">—</span>
|
|
89
|
-
</span>
|
|
90
|
-
</div>
|
|
91
|
-
<div class="match-row">
|
|
92
|
-
<span class="match-label">
|
|
93
|
-
Size
|
|
94
|
-
</span>
|
|
95
|
-
<span class="match-value">
|
|
96
|
-
W:
|
|
97
|
-
<span id="resultWidth">—</span>
|
|
98
|
-
|
|
99
|
-
|
|
|
100
|
-
|
|
101
|
-
H:
|
|
102
|
-
<span id="resultHeight">—</span>
|
|
103
|
-
</span>
|
|
104
|
-
</div>
|
|
105
|
-
</div>
|
|
106
54
|
</section>
|
|
107
55
|
</div>
|
|
108
|
-
|
|
109
56
|
<script src="./src/renderer.js"></script>
|
|
110
57
|
</body>
|
|
111
|
-
</html>
|
|
58
|
+
</html>
|
|
@@ -151,24 +151,21 @@ testMatchBtn.addEventListener("click", async () => {
|
|
|
151
151
|
);
|
|
152
152
|
|
|
153
153
|
if (!result) {
|
|
154
|
-
|
|
155
|
-
document.getElementById('resultConfidence').textContent = "—";
|
|
156
|
-
document.getElementById('resultX').textContent = "—";
|
|
157
|
-
document.getElementById('resultY').textContent = "—";
|
|
158
|
-
document.getElementById('resultWidth').textContent = "—";
|
|
159
|
-
document.getElementById('resultHeight').textContent = "—";
|
|
154
|
+
matchResult.textContent = "✗ MATCH NOT FOUND";
|
|
160
155
|
return;
|
|
161
156
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
document.getElementById('resultConfidence').textContent = data.confidence;
|
|
165
|
-
document.getElementById('resultX').textContent = data.x;
|
|
166
|
-
document.getElementById('resultY').textContent = data.y;
|
|
167
|
-
document.getElementById('resultWidth').textContent = data.width;
|
|
168
|
-
document.getElementById('resultHeight').textContent = data.height;
|
|
169
|
-
};
|
|
157
|
+
matchResult.textContent = `
|
|
158
|
+
✓ MATCH FOUND
|
|
170
159
|
|
|
171
|
-
|
|
160
|
+
Confidence:
|
|
161
|
+
${result.confidence.toFixed(3)}
|
|
162
|
+
|
|
163
|
+
Location:
|
|
164
|
+
(${result.x}, ${result.y})
|
|
165
|
+
|
|
166
|
+
Size:
|
|
167
|
+
${result.width} x ${result.height}
|
|
168
|
+
`;
|
|
172
169
|
});
|
|
173
170
|
|
|
174
171
|
|
package/inspector/styles.css
CHANGED
|
@@ -4,46 +4,51 @@
|
|
|
4
4
|
box-sizing: border-box;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
.
|
|
8
|
-
|
|
7
|
+
.match-summary {
|
|
8
|
+
margin-top: 10px;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
.match-
|
|
12
|
-
|
|
13
|
-
border: 1px solid #444;
|
|
14
|
-
border-radius: 6px;
|
|
15
|
-
margin-bottom: 10px;
|
|
16
|
-
font-weight: bold;
|
|
11
|
+
.match-metric {
|
|
12
|
+
text-align: center;
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
.match-details {
|
|
20
|
-
display: flex;
|
|
21
|
-
flex-direction: column;
|
|
22
|
-
gap: 6px;
|
|
14
|
+
padding: 10px 0;
|
|
23
15
|
}
|
|
24
16
|
|
|
25
|
-
.match-
|
|
26
|
-
|
|
27
|
-
justify-content: space-between;
|
|
28
|
-
padding: 4px 0;
|
|
17
|
+
.match-metric:last-child {
|
|
18
|
+
border-bottom: none;
|
|
29
19
|
}
|
|
30
20
|
|
|
31
|
-
.
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
.metric-label {
|
|
22
|
+
display: block;
|
|
23
|
+
|
|
24
|
+
color: #888;
|
|
25
|
+
|
|
26
|
+
font-size: 0.75em;
|
|
27
|
+
|
|
28
|
+
text-transform: uppercase;
|
|
29
|
+
|
|
30
|
+
letter-spacing: 1px;
|
|
31
|
+
|
|
32
|
+
margin-bottom: 4px;
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
.
|
|
35
|
+
.metric-value {
|
|
36
|
+
display: block;
|
|
37
|
+
|
|
37
38
|
color: #00d4ff;
|
|
38
|
-
font-family: Consolas,
|
|
39
|
-
monospace;
|
|
40
39
|
|
|
40
|
+
font-weight: 700;
|
|
41
|
+
|
|
42
|
+
font-size: 1.2em;
|
|
43
|
+
|
|
44
|
+
font-family: Consolas, monospace;
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
body {
|
|
44
48
|
background: linear-gradient(135deg, #0f0f0f 0%, #1a1a2e 100%);
|
|
45
49
|
color: #e0e0e0;
|
|
46
|
-
font-family: -apple-system, BlinkMacSystemFont,
|
|
50
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
|
51
|
+
sans-serif;
|
|
47
52
|
line-height: 1.6;
|
|
48
53
|
min-height: 100vh;
|
|
49
54
|
}
|
|
@@ -87,7 +92,7 @@ body {
|
|
|
87
92
|
.section-title {
|
|
88
93
|
font-size: 1.2em;
|
|
89
94
|
color: #00d4ff;
|
|
90
|
-
margin-bottom:
|
|
95
|
+
margin-bottom: 2px;
|
|
91
96
|
margin-top: 0;
|
|
92
97
|
font-weight: 600;
|
|
93
98
|
display: flex;
|
|
@@ -198,7 +203,7 @@ input[type="number"] {
|
|
|
198
203
|
background: rgba(37, 37, 38, 0.8);
|
|
199
204
|
color: #00d4ff;
|
|
200
205
|
border: 1px solid rgba(0, 212, 255, 0.3);
|
|
201
|
-
padding:
|
|
206
|
+
padding: 5px 6px;
|
|
202
207
|
border-radius: 6px;
|
|
203
208
|
font-size: 0.8em;
|
|
204
209
|
width: 60px;
|
|
@@ -242,6 +247,7 @@ input[type="number"]:focus {
|
|
|
242
247
|
border-radius: 12px;
|
|
243
248
|
padding: 10px;
|
|
244
249
|
margin-bottom: 10px;
|
|
250
|
+
margin-top: 10px;
|
|
245
251
|
}
|
|
246
252
|
|
|
247
253
|
.template-grid {
|
|
@@ -263,7 +269,7 @@ input[type="number"]:focus {
|
|
|
263
269
|
|
|
264
270
|
.template-status {
|
|
265
271
|
display: inline-block;
|
|
266
|
-
padding:
|
|
272
|
+
padding: 4px 7px;
|
|
267
273
|
background: rgba(76, 175, 80, 0.15);
|
|
268
274
|
border: 1px solid rgba(76, 175, 80, 0.3);
|
|
269
275
|
border-radius: 6px;
|
|
@@ -324,7 +330,6 @@ input[type="number"]:focus {
|
|
|
324
330
|
box-shadow: 0 4px 12px rgba(0, 212, 255, 0.15);
|
|
325
331
|
}
|
|
326
332
|
|
|
327
|
-
|
|
328
333
|
.result-label {
|
|
329
334
|
color: #888;
|
|
330
335
|
font-size: 0.8em;
|
|
@@ -337,7 +342,7 @@ input[type="number"]:focus {
|
|
|
337
342
|
color: #00d4ff;
|
|
338
343
|
font-weight: 700;
|
|
339
344
|
font-size: 0.8em;
|
|
340
|
-
font-family:
|
|
345
|
+
font-family: "Courier New", monospace;
|
|
341
346
|
}
|
|
342
347
|
|
|
343
348
|
#matchResult {
|
|
@@ -347,7 +352,7 @@ input[type="number"]:focus {
|
|
|
347
352
|
background: rgba(37, 37, 38, 0.6);
|
|
348
353
|
border: 1px solid rgba(100, 150, 180, 0.2);
|
|
349
354
|
min-height: 60px;
|
|
350
|
-
display: flex;
|
|
355
|
+
display: inline-flex;
|
|
351
356
|
align-items: center;
|
|
352
357
|
justify-content: center;
|
|
353
358
|
color: #888;
|
|
@@ -408,3 +413,35 @@ input[type="number"]:focus {
|
|
|
408
413
|
::-webkit-scrollbar-thumb:hover {
|
|
409
414
|
background: rgba(0, 212, 255, 0.6);
|
|
410
415
|
}
|
|
416
|
+
|
|
417
|
+
.capture-layout {
|
|
418
|
+
display: grid;
|
|
419
|
+
grid-template-columns: 1fr 280px;
|
|
420
|
+
gap: 16px;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.capture-panel {
|
|
424
|
+
flex: 1;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.result-panel {
|
|
428
|
+
width: 250px;
|
|
429
|
+
|
|
430
|
+
flex-shrink: 0;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
#matchResult {
|
|
434
|
+
padding: 12px;
|
|
435
|
+
|
|
436
|
+
min-height: 157px;
|
|
437
|
+
|
|
438
|
+
background: rgba(255, 255, 255, 0.03);
|
|
439
|
+
|
|
440
|
+
border: 1px solid rgba(0, 212, 255, 0.2);
|
|
441
|
+
|
|
442
|
+
border-radius: 8px;
|
|
443
|
+
|
|
444
|
+
font-family: Consolas, monospace;
|
|
445
|
+
|
|
446
|
+
white-space: pre-line;
|
|
447
|
+
}
|
|
Binary file
|