/
$$.Env.jsxlib
599 lines (501 loc) · 23.7 KB
/
$$.Env.jsxlib
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
/*******************************************************************************
Name: Env
Desc: All about the environment you script is running in.
Path: /core/$$.Env.jsxlib
Require: Enumeration.prototype.revSource
Encoding: ÛȚF8
Core: YES
Kind: Module.
API: =summary() onEngine() onLoad() onUnload() userAgent()
$$.inWin $$.inMac $$.inBin $$.inCC $$.inCS
$$.isDark $$.isHighContrast $$.newLine
system: system()
script: appScriptsPath usrScriptsPath idexEntryPath runningScript
engineState() runCount() session()
idEngine() inBinStream() inStartup()
scriptsPanel() domVersion()->$$ globalEvent()->$$
tempRedraw()->$$ uiLevel()->$$ canToolKit()->$$
application: idVersion()->$$ idFullName()
locale: appLocaleId isValidLocaleId() localeIdToString()
localePrefix()
screen: setActiveScreen() getActiveScreen() screenIndex()
centerWindow()->$$
unit: isUnit()->$$ forceUnit()->$$ toPoints()->$$
user: userName()
DOM-access: GET(app, app.scriptPreferences, app.generalPreferences)
GET(UndoModes, UserInteractionLevels, MeasurementUnits, Locale)
SET(app.scriptPreferences)
Todo: ---
Created: 150507 (YYMMDD)
Modified: 230813 (YYMMDD)
*******************************************************************************/
;eval(__(MODULE, $$, 'Env', 230813, 'summary'))
//==========================================================================
// BACKGROUND
//==========================================================================
/*
The purpose of this core module is to gather various data describing
the environment within which your script (and IdExtenso itself) is
running.
Most of the information is provided by either the `app` instance
(version, locale...) or ExtendScript's helper object (`$.os`,
`$.engineName`...), but important properties are disseminated in
other classes (e.g `Folder.appPackage`) and/or require a bit of
digging. For example, we use a quick test to check whether the
running script is in JSXBIN format (this flag is computed at
including time).
In short the Env module exposes 'all you want to know' to manage
context and/or compatibility issues. It focuses on:
1. The operating system (Mac OS vs. Windows, version.)
2. InDesign version number, environment, files, folders.
3. ExtendScript and ScriptUI (version and build numbers, etc.)
4. IdExtenso related data (version, installed modules.)
5. Script engine and associated properties (persistence, session counter.)
6. Properties of the currently executed script (name, file, etc.)
7. Locale and localization data, user-related data.
In essence, Env is supposed to just answer questions--reason why most
methods are designed as pure 'getters'--and should neither modify the
environment itself nor interact with the DOM system. However, in case
non-neutral changes are to be performed or DOM commands are to be
sent, we still must minimize interactions and restore initial states at
best we can--unless we'd have to circumvent critical errors.
Note. - A few properties computed within this module are 'published'
in the parent module (that is, under $$ itself). For instance:
`inMac`, `inWin`, `newLine`, `inBin`,
`inCC`, `inCS`, `isDark`.
Also, a few features of primary importance are shared with the parent
module, e.g `localeIdToString()`, which makes them available under $$
as well. E.g, `$$.localeIdToString(locId)` is a shortcut of
`$$.Env.localeIdToString(locId)`.
*/
//==========================================================================
// IMPLEMENTATION NOTES
//==========================================================================
/*
1) About app.scriptPreferences. - Trying to retrieve
`app.scriptPreferences.scriptsList` can freeze InDesign for a long
time. This also makes dangerous to access the entire
`app.scriptPreferences.properties` in read mode. (However, setting
`app.scriptPreferences.properties=obj` is safe.)
2) Enable Redraw. - The boolean `app.scriptPreferences.enableRedraw`
is application-persistent. That is, any change made by any script
must be considered a permanent assignation until a new value is set.
3) Active Script (File) vs. $.fileName` (string). - When available,
the command `app.activeScript` returns a File object which points
out to the *main* running script, that is, the one the user has
launched--or made automatic among a `startup scripts` folder. Since
included files or files executed via $.evalFile() are just subparts
of the main program, they are not retrievable from the activeScript
property. [On this topic, see also Section 4.]
By contrast, `$.fileName` reflects (the full path of) the file being
now parsed by the interpreter. In a modular project based on multiple
includes, `$.fileName` is the way to identify the actual subpart of
interest. In addition, `$.fileName` is still reliable in a JSXBIN
stream (contrary to `Error.fileName`.)
Note. - `app.doScript(subFile)` is OK provided subFile has the .jsx
suffix. In that case, it becomes the activeScript during its
execution. IN ANY OTHER CASE, app.activeScript is not available
from within the code executed through app.doScript. For example,
app.doScript( "alert( app.activeScript )" );
causes a runtime error: "No file is associated with the currently
active script." Meanwhile,
app.doScript( "alert( $.fileName )" );
works fine and returns the name of the file *that contains*
app.doScript().
(Also, activeScript is unavailable in ESTK w/ #target indesign.)
As usual, the safe way to conditionnally access the activeScript
property is `app.properties.activeScript`, which returns undefined
when no File is referenced.
4) Binary Stream (JSXBIN). - Regarding compiled code (JSXBIN),
IdExtenso makes a subtle distinction between the MAIN RUNNING
SCRIPT and the CURRENTLY RUNNING CODE. Indeed, one might need
to distinguish between two typical cases:
(a) Your product, based on IdExtenso, is deployed as a
single JSXBIN file, or as a whole `eval(JSXBIN)` line
in a JSX file (which is equivalent here.) The "main
running script" is then a finalized release and it
may be useful to know this fact "from the inside",
in order to accordingly select some behavior, etc.
Full-packed-binary: [ <...> <...> <...> <...> ]
-> Read $$.inBin to access this global flag.
(b) By contrast, during its development, your project is
of course composed of various modules (IdExtenso's
bricks and your own code...) Incidentally, it can
involve compiled parts, thru eval() or similar means,
while the main program is not yet assembled as a whole.
For example, suppose a specific IdExtenso module is
encoded and delivered in the `eval(JSXBIN)` form. In
such case the module may want to check whether it
is itself JSXBIN-compiled *regardless of the status
of its containing project*. The "current running
stream" adresses this specific question, which is
answered dynamically by parsing $.stack.
Partial-binary: [ <IdEx> <..^..> <Code> <Code> ]
-> Call $$.Env.inBinStream() to access this property.
5) List of Basic Predefined Folders.
Folder.myDocuments "My Documents" folder associated to the user.
------------------------------------------------------------------
Folder.system Folder that contains the OS files
(e.g /System [MAC] ; /c/Windows [WIN])
------------------------------------------------------------------
Folder.temp Default folder for temporary files.
[REM] Not to be confused with
`app.generalPreferences.temporaryFolder`.
------------------------------------------------------------------
Folder.userData Location of user's application data.
------------------------------------------------------------------
Folder.appData Location of application data for all users.
------------------------------------------------------------------
Folder.desktop Desktop (e.g ~/Desktop, ~/Bureau, etc.)
------------------------------------------------------------------
Folder.current (R/W) Get/set the current folder, from which
relative URIs are to be resolved.
(session-persistent.)
6) ExtendScript engines. - [SDK] InDesign has two types of
ExtendScript engines. Each type of engine supports the same
scripting DOM and other capabilities:
- The default engine, named "main," is created automatically and is
reset after each time it executes a script.
- Persistent session engines, which exist until the application quits
and are not reset, may be created at any time by running a script with
a #targetengine directive. The engine will have whatever name is
specified in the #targetengine directive. It retains objects and
properties between scripts. This is important for scripts attached as
function callbacks, such as event handlers, which must remain active
after they are attached. It also is a requirement for scripts that
display floating script user-interface panels, which may float around
indefinitely during an entire user session. The engine is visible to
the debugger.
To target a specific engine, use the #targetengine directive at the
beginning of your script. For example, the following code executes the
script in an engine named "mySession":
#targetengine "mySession"
You may use `#targetengine "main"` to target the main engine. However,
there is no reason to do so, since scripts are run in the main engine
by default.
If a #targetengine directive specifies an engine name that InDesign
does not recognize, InDesign automatically creates a persistent engine
with that name. This feature prevents conflicts caused by other
scripts changing objects/values your script uses. To specify your own
script engine, simply put `#targetengine <your engine name>` at the
top of your script.
You also can create an ExtendScript engine via the C++ API (see the
IExtendScriptUtils interface). There are three customizable
options: engine name, whether the engine is reset after every script,
and whether the engine is visible to the debugger.
7a) WINDOWS Environment Variables. Win platforms provide a set of
env variables available to `$.getenv(<ENV_VAR_NAME>)`. Variable names
are case-insensitive. $.getenv returns NULL if the variable is
unknown/undefined. Here is a set of relevant vars that should be
defined on most platforms:
VARIABLE NAME TYPICAL RESULT
-----------------------------------------------------------
ALLUSERSPROFILE "C:\ProgramData"
APPDATA "C:\Users\<User>\AppData\Roaming"
COMPUTERNAME <ComputerName>
COMSPEC "C:\Windows\system32\cmd.exe"
HOMEDRIVE "C:"
HOMEPATH "\Users\<User>"
LOCALAPPDATA "C:\Users\<User>\AppData\Local"
LOGONSERVER "\\<ServerName>"
NUMBER_OF_PROCESSORS "8"
OS "Windows_NT"
PATH "c:\windows\system32;c:\windows;<etc>"
PATHEXT ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WSH;<etc>"
PROCESSOR_ARCHITECTURE "AMD64"
PROCESSOR_IDENTIFIER "Intel64 Family 6..."
PROGRAMDATA "C:\ProgramData"
PROGRAMFILES "C:\Program Files"
PUBLIC "C:\Users\Public"
SYSTEMDRIVE "C:"
SYSTEMROOT "C:\Windows"
TEMP "C:\Users\<User>\AppData\Local\Temp"
TMP "C:\Users\<User>\AppData\Local\Temp"
USERDOMAIN <Domain>
USERNAME <User>
USERPROFILE "C:\Users\<User>"
WINDIR "C:\Windows"
[RES] en.wikipedia.org/wiki/Environment_variable
8) About $.setenv and $.getenv.
- $.setenv(paramStr,valueStr) set a variable session-persistently. It
can store a UTF16 string of arbitrary length, but the NUL character
U+0000 is considered string termination. So, for example,
$.setenv('MYPARAM',"abc\x00def")
actually stores "abc", so that `$.getenv('MYPARAM')==="abc"`.
Note that `setenv` 2nd argument, if present, is coerced into a string,
so even null will become "null"! If no 2nd argument is supplied, the
function *has no effect* (the environment parameter is not removed.)
The way to remove a parameter is to explicitly pass an empty string:
$.setenv('MYPARAM','') // remove MYPARAM
The 1st argument is case-insensitive:
$.setenv('My Test',"abc");
$.getenv('MY TEST'); // => "abc"
It supports arbitrary length and can contain any non-NUL character.
- $.getenv(paramStr) returns a string if paramStr is defined, otherwise
it returns null.
As seen in the previous section, a number of OS-oriented environment
variables are defined by default. To make sure you don't attempt to
overwrite an existing parameter, you should check whether
null !== $.getenv(paramStr)
before processing.
*/
[PRIVATE]
({
// [FIX190311] The previous version was checking IDEX from Env/script, which
// failed! Indeed, I wrongly thought that in include mode `$.fileName` was
// referring to the being-included file. This is not correct: `$.fileName`
// refers to the included file *that contains the ExtendScript command being
// presently executed*, that is, `eval(...)[PRIVATE](...)...[PUBLIC](...)` etc.
// The parts included within that single command --e.g Env/$$.system.jsxinc--
// do not cause `$.fileName` to match their own file name. So, `$.fileName`
// remains "(...)$$.Env.jsxlib" throughout the entire Env inclusion. To avoid
// any confusion, it's therefore preferable to run the IDEX test here, which
// is now done in one step. The private ~.REGF regex has been removed.
// ---
// [REM180513] ~.IDEX contains the full path to IdExtenso's Entry Point if
// available ; otherwise it is set to FALSE. The test relies on two conditions:
// 1. The temporary global `__jsxinc__` must match "(...)$$.jsxinc"
// 2. `$.fileName` must match "(...)$$.Env.jsxlib"
// ---
// [REM190202] Still works if an alternate entry point is used, since __jsxinc__ is
// set from within the $$.jsxinc file.
// ---
IDEX :
[
( /\$\$\.jsxinc$/.test(__jsxinc__) && /\$\$\.Env\.jsxlib$/.test($.fileName) && __jsxinc__ ),
( delete $.global.__jsxinc__ ) // Autodelete the global once checked
][0],
})
//==========================================================================
// [190202] INCLUDE SUB SNIPPETS -- order matters!
//==========================================================================
#include 'Env/$$.system.jsxinc'
#include 'Env/$$.script.jsxinc'
#include 'Env/$$.application.jsxinc'
#include 'Env/$$.locale.jsxinc'
#include 'Env/$$.screen.jsxinc'
#include 'Env/$$.unit.jsxinc'
#include 'Env/$$.user.jsxinc'
//==========================================================================
// API
//==========================================================================
[PUBLIC]
({
onEngine: function onEngine_()
//----------------------------------
// [ADD170511] Refine ~.OSYS on Win platforms.
{
callee.µ['~'].RSYS();
},
onLoad: function onLoad_( $$,I,q,t)
//----------------------------------
// [ADD190202] Determine the active screen at load time.
{
$$ = $.global[callee.µ.__root__]; // agnostic reference
I = callee.µ['~']; // inner zone
$$.kill(q=callee.Q||(callee.Q={})); // cache (emptied.)
// Folder.current backup.
// ---
I.CURF(1);
// ExtendScript localizer: backup, and
// set to FALSE if Yalt is in the place!
// ---
if( 1===I.ESLZ(1) && $$.Yalt )
{
(+$$.trace) && $$.trace(__("%1 > Deactivate $.localize (makes room to Yalt.)",callee.µ));
$.localize = false;
}
// If the engine is either non-persistent or in first-call stage,
// (that is, if ENST!=0) there is no need to update ~.SPRF
// since this has been already performed at including stage.
// Otherwise, we have to call ~.SPRF(1) to make sure all
// current script preferences are properly registered from now.
// [ADD220601] Update HIGH contrast flag too.
// ---
I.ENST || ( I.SPRF(1), ($$.isDark=I.DARK(1),$$.isHighContrast=I.DARK.HIGH) );
// Backup <ScPrefs>.version (should be app.version at this point!)
// ---
I.DOMV(1);
// Backup EnableRedraw and forcibly set it to TRUE.
// ---
1===I.RDRW(1) || (q.enableRedraw=true);
// Backup UserInteractionLevel and forcibly set it to INTERACT_WITH_ALL.
// ---
t = +UserInteractionLevels.INTERACT_WITH_ALL;
t===I.UILV(1) || (q.userInteractionLevel=t);
// Backup <ScPrefs>.measurementUnit.
// ---
I.SCMU(1);
delete callee.µ.forceUnit.FORCE_MU_BKP; // [ADD230811] Safer. [CHG230813] Cached in µ.forceUnit.
// [ADD190202] Determine the active screen if possible.
// ---
I.W2AC();
// Apply IdExtenso script preferences (if changes are required.)
// ---
if( q.__count__ )
{
(+$$.trace) && $$.trace(__("%1 > Change script preferences to %2.",callee.µ,$$.JSON(q,0,1)));
app.scriptPreferences.properties = q;
// Update ~.SPRF to keep it in sync.
// ---
I.SPRF(1);
}
// Trace Env.summary().
// ---
(+$$.trace) && $$.trace(__("%1 > %2",callee.µ,callee.µ.summary($$.newLine+$$.Log.spaces)));
},
onUnload: function onUnload_( $$,I,q)
//----------------------------------
// [CHG230811] Manage internal `FORCE_MU_BKP` in CS4 -- cf unit > forceUnit().
// [CHG230813] Better implementation -> delegates to `µ.forceUnit()`.
{
$$ = $.global[callee.µ.__root__]; // agnostic reference
I = callee.µ['~']; // inner zone
$$.kill(q=callee.Q||(callee.Q={})); // cache (emptied.)
// As we don't know what the hell the client code has
// done until now, we MUST call ~.SPRF(1) again to make
// sure prefs are properly addressed before processing.
// ---
I.SPRF(1);
// (a) Restore viewPrefs units in CS4 when $$.Env.forceUnit has been invoked
// or
// (b) Restore app.scriptPreferences.measurementUnit in CC/CS6/CS5
// [CHG230813] Much cleaner to let `µ.forceUnit(false)` do the job.
// Also, the `I.SCMU(0)` test is no longer needed after that.
// ---
callee.µ.forceUnit(false);
// Restore script prefs (if needed.)
// ---
I.DOMV(0) && (q.version=I.DOMV());
I.RDRW(0) && (q.enableRedraw=I.RDRW());
I.UILV(0) && (q.userInteractionLevel=I.UILV());
// I.SCMU(0) && (q.measurementUnit=I.SCMU()); [DEL230813] No longer needed due to `forceUnit(false).`
if( q.__count__ )
{
(+$$.trace) && $$.trace(__("%1 > Restore script preferences to %2.",callee.µ,$$.JSON(q,0,1)));
app.scriptPreferences.properties = q;
I.SPRF(1); // update ~.SPRF to keep it in sync.
}
// Restore ExtendScript localizer.
// ---
if( I.ESLZ(0) )
{
(+$$.trace) && $$.trace(__("%1 > Restore $.localize=%2.",callee.µ,I.ESLZ()));
$.localize=I.ESLZ();
}
// Restore Folder.current.
// ---
if( I.CURF(0) )
{
(+$$.trace) && $$.trace(__("%1 > Restore Folder.current=%2.",callee.µ,I.CURF().toSource()));
Folder.current = I.CURF();
}
},
summary: function summary_s_S(/*str=$$.newLine*/sep, $$,I,q,t,prf,screens,codeStream)
//----------------------------------
// [UPD170419] Collect and return interesting environment data.
// [ADD180401] Added screen data.
// [UPD210106] ESTK status (cf. ~.ESTK.)
// [ADD210403] Added 'startup script stage'
// `sep` :: line separator (default: $$.newLine)
// ---
// [CHG170408] =auto. So you can run `alert($$.Env())`
// => str
{
$$ = $.global[callee.µ.__root__]; // agnostic reference
I = callee.µ['~']; // inner zone
(q = callee.Q||(callee.Q=[])).length = 0;
sep = 'undefined' == typeof sep ? $$.newLine : String(sep);
// Update inner script prefs.
// ---
I.SPRF(1);
prf = __('Redraw=%1 ; Level=%2 ; Unit=%3',
!!(t=I.SPRF()).enableRedraw,
I.UL2S[t.userInteractionLevel],
I.MU2S[t.measurementUnit]
);
// [ADD180402] Display.
// ---
t = I.SCRN.Q;
screens = __("Screens: %1 ; %2Primary #%3: [%4]x[%5]"
, t.length
, t.CURRENT_PPI ? (t.CURRENT_PPI + ' ppi ; ') : ''
, t.PRIM
, t[t.PRIM][1] + ',' + t[t.PRIM][3]
, t[t.PRIM][0] + ',' + t[t.PRIM][2]
);
if( t.hasOwnProperty('ACTV') && t.ACTV!=t.PRIM )
{
screens += __(" ; Active #%1: [%2]x[%3]"
, t.ACTV
, t[t.ACTV][1] + ',' + t[t.ACTV][3]
, t[t.ACTV][0] + ',' + t[t.ACTV][2]
);
}
screens += __(" ; Workspace: [%1]x[%2]"
, t.SUIB[1] + ',' + t.SUIB[3]
, t.SUIB[0] + ',' + t.SUIB[2]
);
// Dynamic check of the stream (BIN vs. JSX)
// ---
codeStream = I.JXBN ?
( "Main BIN Stream" ) :
( (t=I.BSTK()) ? __("Inner BIN Stream [%1]",t) : "JSX Stream" );
// [190126] Better formatting of IdExtenso's version.
// [220601] Mid vs High contrasted UI.
// ---
return [
__("OS: %1", I.OSYS),
__("InDesign: %1 [%2-%3 UI]",I.IDNM, $$.isHighContrat?'High':'Mid', $$.isDark?'Dark':'Bright'),
__("ExtendScript: %1 [ESTK %2]", I.ESVS, I.ESTK()),
__("ScriptUI: %1", I.SUVS),
__("IdExtenso: %1 [run #%2 in session '%3']", String($$.__modf__)[0]+'.'+String($$.__modf__).slice(1), callee.µ.runCount(), callee.µ.session()),
__("Engine: %1 [%2]%3", I.ENGI.toSource(),callee.µ.engineState(1),callee.µ.inStartup()?' [startup script stage]':''),
__("Script (%1): %2 [%3]", (I.JXBN?'BIN':'JSX'),(t=File(I.SCPT)).displayName, t.parent.fullName),
__("DOM version: %1 [%2]", (t=I.SPRF().version), parseFloat(t)<I.IDNB ? 'LOWER!' : 'OK'),
__("Undo Mode: %1", I.SCUM),
__("Preferences: %1", prf),
__("Display: %1", screens),
__("User: %1%2 on %3", I.OSUS.toSource(),
( I.IDUS==I.UNKU ? '' : __(" [aka: %1]",I.IDUS) ),
I.OSCP
),
__("Locale: %1/%2", I.LPFX, I.LANG),
__("Running Code: %1", codeStream)
].join(sep);
},
userAgent: function userAgent_S()
//----------------------------------
// Return a 'user agent' identification string.
// [RES] <tools.ietf.org/html/rfc7231#section-5.5.3>
// <en.wikipedia.org/wiki/User_agent#User_agent_identification>
// E.g => "IdExtenso/1.70403 ExtendScript/3.92 Adobe-InDesign/6.0.6.622"
// => str
{
return __("IdExtenso/%1 ExtendScript/%2 Adobe-InDesign/%3",
$.global[callee.µ.__root__].__modf__/1e5,
callee.µ['~'].ESNB,
callee.µ['~'].IDVS
);
},
})
[PARENT]
({
// Mac OS Unix :: <LF> ie \n
// Classic Mac OS :: <CR> ie \r [obsolete]
// Windows :: <CR> ie \r [<CRLF> is not needed]
// ---
newLine : µ['~'].OSMC ? String.LF : String.CR,
inMac : +µ['~'].OSMC,
inWin : 1 -µ['~'].OSMC,
// Tell whether the script (=main program) is a JSXBIN.
// [REM] The `inBin` flag is fixed at including stage.
// To dynamically check whether the current code belongs
// to a JSXBIN stream, use Env.inBinStream() rather.
// ---
inBin : µ['~'].JXBN,
inCC : +(9 <= µ['~'].IDNB),
inCS : +(9 > µ['~'].IDNB),
isDark : µ['~'].DARK(),
isHighContrast: µ['~'].DARK.HIGH, // [ADD220602] The inner HIGH flag tells whether DARK or non-DARK UI is in high contrast. Always 1 in CS (-> non-DARK.)
})