@forgerock/login-widget 1.0.0-beta.14 → 1.0.0-beta.16
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/CHANGELOG.md +14 -0
- package/index.cjs +67 -49
- package/index.cjs.map +1 -1
- package/index.d.ts +3 -0
- package/index.js +67 -49
- package/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [1.0.0-beta.16](https://github.com/forgerock/forgerock-web-login-framework/compare/v1.0.0-beta.15...v1.0.0-beta.16) (2023-03-30)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **confirm-input:** make confirm input required when password is filled ([0c8325c](https://github.com/forgerock/forgerock-web-login-framework/commit/0c8325cd2e0a9959c3a88b2e4aa8abd6e931456b))
|
|
7
|
+
|
|
8
|
+
# [1.0.0-beta.15](https://github.com/forgerock/forgerock-web-login-framework/compare/v1.0.0-beta.14...v1.0.0-beta.15) (2023-03-27)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **login-failure:** handle 500 failures within login store ([90fb461](https://github.com/forgerock/forgerock-web-login-framework/commit/90fb461e2598f929e4b418c9794f8b085e433e54))
|
|
14
|
+
|
|
1
15
|
# [1.0.0-beta.14](https://github.com/forgerock/forgerock-web-login-framework/compare/v1.0.0-beta.13...v1.0.0-beta.14) (2023-03-27)
|
|
2
16
|
|
|
3
17
|
|
package/index.cjs
CHANGED
|
@@ -16829,6 +16829,7 @@ var tryAgain = "Please try again";
|
|
|
16829
16829
|
var twoFactorAuthentication = "Two factor authentication";
|
|
16830
16830
|
var useValidEmail = "Please use a valid email address.";
|
|
16831
16831
|
var unrecoverableError = "There was an error in the form submission.";
|
|
16832
|
+
var unknownLoginError = "Unknown login failure has occurred.";
|
|
16832
16833
|
var unknownNetworkError = "Unknown network request failure has occurred.";
|
|
16833
16834
|
var userName = "Username";
|
|
16834
16835
|
var usernameRequirements = "Username requirements:";
|
|
@@ -16907,6 +16908,7 @@ var fallback = {
|
|
|
16907
16908
|
twoFactorAuthentication: twoFactorAuthentication,
|
|
16908
16909
|
useValidEmail: useValidEmail,
|
|
16909
16910
|
unrecoverableError: unrecoverableError,
|
|
16911
|
+
unknownLoginError: unknownLoginError,
|
|
16910
16912
|
unknownNetworkError: unknownNetworkError,
|
|
16911
16913
|
userName: userName,
|
|
16912
16914
|
usernameRequirements: usernameRequirements,
|
|
@@ -16988,6 +16990,7 @@ const stringsSchema = z
|
|
|
16988
16990
|
twoFactorAuthentication: z.string(),
|
|
16989
16991
|
useValidEmail: z.string(),
|
|
16990
16992
|
unrecoverableError: z.string(),
|
|
16993
|
+
unknownLoginError: z.string(),
|
|
16991
16994
|
unknownNetworkError: z.string(),
|
|
16992
16995
|
userName: z.string(),
|
|
16993
16996
|
usernameRequirements: z.string(),
|
|
@@ -17002,9 +17005,10 @@ stringsSchema.partial();
|
|
|
17002
17005
|
stringsSchema.parse(fallback);
|
|
17003
17006
|
const stringsStore = writable(null);
|
|
17004
17007
|
/**
|
|
17005
|
-
* initialize
|
|
17006
|
-
* @param
|
|
17007
|
-
* @returns
|
|
17008
|
+
* @function initialize - Initialize the locale store
|
|
17009
|
+
* @param {object} userLocale - An object of custom locale strings to merge with the default
|
|
17010
|
+
* @returns {object} - The locale store
|
|
17011
|
+
* @example initialize({ loginHeader: 'Welcome to the login page' });
|
|
17008
17012
|
*/
|
|
17009
17013
|
function initialize$5(userLocale) {
|
|
17010
17014
|
if (userLocale) {
|
|
@@ -17456,6 +17460,11 @@ function buildStepMetadata(callbackMetadataArray, stageJson, stageName) {
|
|
|
17456
17460
|
};
|
|
17457
17461
|
}
|
|
17458
17462
|
|
|
17463
|
+
/**
|
|
17464
|
+
* @function initializeJourney - Initializes the journey stack for tracking journey switches
|
|
17465
|
+
* @param {object} initOptions - The initial options to set
|
|
17466
|
+
* @returns {object} - The journey stack store with stack methods
|
|
17467
|
+
*/
|
|
17459
17468
|
function initializeStack(initOptions) {
|
|
17460
17469
|
const initialValue = initOptions ? [initOptions] : [];
|
|
17461
17470
|
const { update, set, subscribe } = writable(initialValue);
|
|
@@ -17519,6 +17528,11 @@ const journeyStore = writable({
|
|
|
17519
17528
|
successful: false,
|
|
17520
17529
|
response: null,
|
|
17521
17530
|
});
|
|
17531
|
+
/**
|
|
17532
|
+
* @function initialize - Initializes the journey store
|
|
17533
|
+
* @param {object} initOptions - The initial options to set
|
|
17534
|
+
* @returns {object} - The journey store
|
|
17535
|
+
*/
|
|
17522
17536
|
function initialize$4(initOptions) {
|
|
17523
17537
|
const stack = initializeStack();
|
|
17524
17538
|
let stepNumber = 0;
|
|
@@ -17638,7 +17652,7 @@ function initialize$4(initOptions) {
|
|
|
17638
17652
|
*
|
|
17639
17653
|
* Grab failure message, which may contain encoded HTML
|
|
17640
17654
|
*/
|
|
17641
|
-
const failureMessageStr = htmlDecode(nextStep.payload.message || '');
|
|
17655
|
+
const failureMessageStr = htmlDecode(nextStep.payload.message || 'Unknown login error');
|
|
17642
17656
|
let restartedStep = null;
|
|
17643
17657
|
try {
|
|
17644
17658
|
/**
|
|
@@ -23102,7 +23116,7 @@ function get_each_context$7(ctx, list, i) {
|
|
|
23102
23116
|
return child_ctx;
|
|
23103
23117
|
}
|
|
23104
23118
|
|
|
23105
|
-
// (
|
|
23119
|
+
// (39:0) {#if labelOrder === 'first'}
|
|
23106
23120
|
function create_if_block_1$a(ctx) {
|
|
23107
23121
|
let label_1;
|
|
23108
23122
|
let current;
|
|
@@ -23150,7 +23164,7 @@ function create_if_block_1$a(ctx) {
|
|
|
23150
23164
|
};
|
|
23151
23165
|
}
|
|
23152
23166
|
|
|
23153
|
-
// (
|
|
23167
|
+
// (40:2) <Label {key} classes={`${labelClasses}`}>
|
|
23154
23168
|
function create_default_slot_1$b(ctx) {
|
|
23155
23169
|
let t;
|
|
23156
23170
|
|
|
@@ -23170,7 +23184,7 @@ function create_default_slot_1$b(ctx) {
|
|
|
23170
23184
|
};
|
|
23171
23185
|
}
|
|
23172
23186
|
|
|
23173
|
-
// (
|
|
23187
|
+
// (54:2) {#each options as option}
|
|
23174
23188
|
function create_each_block$7(ctx) {
|
|
23175
23189
|
let option;
|
|
23176
23190
|
let t0_value = /*option*/ ctx[15].text + "";
|
|
@@ -23211,7 +23225,7 @@ function create_each_block$7(ctx) {
|
|
|
23211
23225
|
};
|
|
23212
23226
|
}
|
|
23213
23227
|
|
|
23214
|
-
// (
|
|
23228
|
+
// (61:0) {#if labelOrder === 'last'}
|
|
23215
23229
|
function create_if_block$g(ctx) {
|
|
23216
23230
|
let label_1;
|
|
23217
23231
|
let current;
|
|
@@ -23264,7 +23278,7 @@ function create_if_block$g(ctx) {
|
|
|
23264
23278
|
};
|
|
23265
23279
|
}
|
|
23266
23280
|
|
|
23267
|
-
// (
|
|
23281
|
+
// (62:2) <Label {key} classes={`${shouldDisplayOption ? labelClasses : 'tw_sr-only'}`}>
|
|
23268
23282
|
function create_default_slot$i(ctx) {
|
|
23269
23283
|
let t;
|
|
23270
23284
|
|
|
@@ -23503,8 +23517,6 @@ function instance$E($$self, $$props, $$invalidate) {
|
|
|
23503
23517
|
// Check if text is same as label
|
|
23504
23518
|
$$invalidate(10, shouldDisplayOption = !(label === selectedOption?.text));
|
|
23505
23519
|
|
|
23506
|
-
console.log(shouldDisplayOption);
|
|
23507
|
-
|
|
23508
23520
|
// Continue with calling onChange parameter
|
|
23509
23521
|
onChange(event);
|
|
23510
23522
|
}
|
|
@@ -27391,8 +27403,8 @@ class Eye_icon extends SvelteComponent {
|
|
|
27391
27403
|
|
|
27392
27404
|
function create_default_slot_1$8(ctx) {
|
|
27393
27405
|
let current;
|
|
27394
|
-
const default_slot_template = /*#slots*/ ctx[
|
|
27395
|
-
const default_slot = create_slot(default_slot_template, ctx, /*$$scope*/ ctx[
|
|
27406
|
+
const default_slot_template = /*#slots*/ ctx[15].default;
|
|
27407
|
+
const default_slot = create_slot(default_slot_template, ctx, /*$$scope*/ ctx[16], null);
|
|
27396
27408
|
|
|
27397
27409
|
return {
|
|
27398
27410
|
c() {
|
|
@@ -27407,15 +27419,15 @@ function create_default_slot_1$8(ctx) {
|
|
|
27407
27419
|
},
|
|
27408
27420
|
p(ctx, dirty) {
|
|
27409
27421
|
if (default_slot) {
|
|
27410
|
-
if (default_slot.p && (!current || dirty & /*$$scope*/
|
|
27422
|
+
if (default_slot.p && (!current || dirty & /*$$scope*/ 65536)) {
|
|
27411
27423
|
update_slot_base(
|
|
27412
27424
|
default_slot,
|
|
27413
27425
|
default_slot_template,
|
|
27414
27426
|
ctx,
|
|
27415
|
-
/*$$scope*/ ctx[
|
|
27427
|
+
/*$$scope*/ ctx[16],
|
|
27416
27428
|
!current
|
|
27417
|
-
? get_all_dirty_from_scope(/*$$scope*/ ctx[
|
|
27418
|
-
: get_slot_changes(default_slot_template, /*$$scope*/ ctx[
|
|
27429
|
+
? get_all_dirty_from_scope(/*$$scope*/ ctx[16])
|
|
27430
|
+
: get_slot_changes(default_slot_template, /*$$scope*/ ctx[16], dirty, null),
|
|
27419
27431
|
null
|
|
27420
27432
|
);
|
|
27421
27433
|
}
|
|
@@ -27436,7 +27448,7 @@ function create_default_slot_1$8(ctx) {
|
|
|
27436
27448
|
};
|
|
27437
27449
|
}
|
|
27438
27450
|
|
|
27439
|
-
// (
|
|
27451
|
+
// (69:4) <EyeIcon classes="tw_password-icon dark:tw_password-icon_dark" visible={isVisible}>
|
|
27440
27452
|
function create_default_slot$f(ctx) {
|
|
27441
27453
|
let t;
|
|
27442
27454
|
let current;
|
|
@@ -27466,7 +27478,7 @@ function create_default_slot$f(ctx) {
|
|
|
27466
27478
|
};
|
|
27467
27479
|
}
|
|
27468
27480
|
|
|
27469
|
-
// (
|
|
27481
|
+
// (63:2)
|
|
27470
27482
|
function create_input_button_slot$1(ctx) {
|
|
27471
27483
|
let button;
|
|
27472
27484
|
let eyeicon;
|
|
@@ -27497,7 +27509,7 @@ function create_input_button_slot$1(ctx) {
|
|
|
27497
27509
|
current = true;
|
|
27498
27510
|
|
|
27499
27511
|
if (!mounted) {
|
|
27500
|
-
dispose = listen(button, "click", /*toggleVisibility*/ ctx[
|
|
27512
|
+
dispose = listen(button, "click", /*toggleVisibility*/ ctx[11]);
|
|
27501
27513
|
mounted = true;
|
|
27502
27514
|
}
|
|
27503
27515
|
},
|
|
@@ -27505,7 +27517,7 @@ function create_input_button_slot$1(ctx) {
|
|
|
27505
27517
|
const eyeicon_changes = {};
|
|
27506
27518
|
if (dirty & /*isVisible*/ 64) eyeicon_changes.visible = /*isVisible*/ ctx[6];
|
|
27507
27519
|
|
|
27508
|
-
if (dirty & /*$$scope*/
|
|
27520
|
+
if (dirty & /*$$scope*/ 65536) {
|
|
27509
27521
|
eyeicon_changes.$$scope = { dirty, ctx };
|
|
27510
27522
|
}
|
|
27511
27523
|
|
|
@@ -27533,18 +27545,16 @@ function create_fragment$q(ctx) {
|
|
|
27533
27545
|
let input;
|
|
27534
27546
|
let current;
|
|
27535
27547
|
|
|
27536
|
-
input = new /*Input*/ ctx[
|
|
27548
|
+
input = new /*Input*/ ctx[9]({
|
|
27537
27549
|
props: {
|
|
27538
27550
|
forceValidityFailure: /*forceValidityFailure*/ ctx[0],
|
|
27539
27551
|
isFirstInvalidInput: false,
|
|
27540
27552
|
hasRightIcon: true,
|
|
27541
27553
|
key: `${/*key*/ ctx[3]}-confirm`,
|
|
27542
27554
|
label: interpolate('confirmPassword', null, 'Confirm Password'),
|
|
27543
|
-
message: /*
|
|
27544
|
-
|
|
27545
|
-
:
|
|
27546
|
-
onChange: /*onChangeWrapper*/ ctx[9],
|
|
27547
|
-
isInvalid: /*isInvalid*/ ctx[1],
|
|
27555
|
+
message: /*message*/ ctx[8],
|
|
27556
|
+
onChange: /*onChangeWrapper*/ ctx[10],
|
|
27557
|
+
isInvalid: /*passwordsDoNotMatch*/ ctx[1],
|
|
27548
27558
|
isRequired: /*isRequired*/ ctx[2],
|
|
27549
27559
|
showMessage: /*showMessage*/ ctx[4],
|
|
27550
27560
|
type: /*type*/ ctx[7],
|
|
@@ -27571,12 +27581,8 @@ function create_fragment$q(ctx) {
|
|
|
27571
27581
|
const input_changes = {};
|
|
27572
27582
|
if (dirty & /*forceValidityFailure*/ 1) input_changes.forceValidityFailure = /*forceValidityFailure*/ ctx[0];
|
|
27573
27583
|
if (dirty & /*key*/ 8) input_changes.key = `${/*key*/ ctx[3]}-confirm`;
|
|
27574
|
-
|
|
27575
|
-
if (dirty & /*
|
|
27576
|
-
? interpolate('passwordConfirmationError', null, 'Passwords do not match')
|
|
27577
|
-
: undefined;
|
|
27578
|
-
|
|
27579
|
-
if (dirty & /*isInvalid*/ 2) input_changes.isInvalid = /*isInvalid*/ ctx[1];
|
|
27584
|
+
if (dirty & /*message*/ 256) input_changes.message = /*message*/ ctx[8];
|
|
27585
|
+
if (dirty & /*passwordsDoNotMatch*/ 2) input_changes.isInvalid = /*passwordsDoNotMatch*/ ctx[1];
|
|
27580
27586
|
if (dirty & /*isRequired*/ 4) input_changes.isRequired = /*isRequired*/ ctx[2];
|
|
27581
27587
|
if (dirty & /*showMessage*/ 16) input_changes.showMessage = /*showMessage*/ ctx[4];
|
|
27582
27588
|
if (dirty & /*type*/ 128) input_changes.type = /*type*/ ctx[7];
|
|
@@ -27585,7 +27591,7 @@ function create_fragment$q(ctx) {
|
|
|
27585
27591
|
? /*value*/ ctx[5]
|
|
27586
27592
|
: '';
|
|
27587
27593
|
|
|
27588
|
-
if (dirty & /*$$scope, isVisible*/
|
|
27594
|
+
if (dirty & /*$$scope, isVisible*/ 65600) {
|
|
27589
27595
|
input_changes.$$scope = { dirty, ctx };
|
|
27590
27596
|
}
|
|
27591
27597
|
|
|
@@ -27609,8 +27615,8 @@ function create_fragment$q(ctx) {
|
|
|
27609
27615
|
function instance$q($$self, $$props, $$invalidate) {
|
|
27610
27616
|
let { $$slots: slots = {}, $$scope } = $$props;
|
|
27611
27617
|
let { forceValidityFailure = false } = $$props;
|
|
27612
|
-
let {
|
|
27613
|
-
let { isRequired =
|
|
27618
|
+
let { passwordsDoNotMatch = false } = $$props;
|
|
27619
|
+
let { isRequired = false } = $$props;
|
|
27614
27620
|
let { key } = $$props;
|
|
27615
27621
|
let { onChange } = $$props;
|
|
27616
27622
|
let { resetValue } = $$props;
|
|
@@ -27620,6 +27626,7 @@ function instance$q($$self, $$props, $$invalidate) {
|
|
|
27620
27626
|
let isVisible = false;
|
|
27621
27627
|
let type = 'password';
|
|
27622
27628
|
let value;
|
|
27629
|
+
let message = '';
|
|
27623
27630
|
|
|
27624
27631
|
function onChangeWrapper(event) {
|
|
27625
27632
|
$$invalidate(5, value = event.target?.value);
|
|
@@ -27638,36 +27645,45 @@ function instance$q($$self, $$props, $$invalidate) {
|
|
|
27638
27645
|
|
|
27639
27646
|
$$self.$$set = $$props => {
|
|
27640
27647
|
if ('forceValidityFailure' in $$props) $$invalidate(0, forceValidityFailure = $$props.forceValidityFailure);
|
|
27641
|
-
if ('
|
|
27648
|
+
if ('passwordsDoNotMatch' in $$props) $$invalidate(1, passwordsDoNotMatch = $$props.passwordsDoNotMatch);
|
|
27642
27649
|
if ('isRequired' in $$props) $$invalidate(2, isRequired = $$props.isRequired);
|
|
27643
27650
|
if ('key' in $$props) $$invalidate(3, key = $$props.key);
|
|
27644
|
-
if ('onChange' in $$props) $$invalidate(
|
|
27645
|
-
if ('resetValue' in $$props) $$invalidate(
|
|
27646
|
-
if ('style' in $$props) $$invalidate(
|
|
27651
|
+
if ('onChange' in $$props) $$invalidate(12, onChange = $$props.onChange);
|
|
27652
|
+
if ('resetValue' in $$props) $$invalidate(13, resetValue = $$props.resetValue);
|
|
27653
|
+
if ('style' in $$props) $$invalidate(14, style = $$props.style);
|
|
27647
27654
|
if ('showMessage' in $$props) $$invalidate(4, showMessage = $$props.showMessage);
|
|
27648
|
-
if ('$$scope' in $$props) $$invalidate(
|
|
27655
|
+
if ('$$scope' in $$props) $$invalidate(16, $$scope = $$props.$$scope);
|
|
27649
27656
|
};
|
|
27650
27657
|
|
|
27651
27658
|
$$self.$$.update = () => {
|
|
27652
|
-
if ($$self.$$.dirty & /*resetValue, onChange, value*/
|
|
27659
|
+
if ($$self.$$.dirty & /*resetValue, onChange, value, passwordsDoNotMatch, isRequired*/ 12326) {
|
|
27653
27660
|
{
|
|
27654
27661
|
if (resetValue) {
|
|
27655
27662
|
$$invalidate(5, value = undefined);
|
|
27656
27663
|
onChange(value);
|
|
27657
27664
|
}
|
|
27665
|
+
|
|
27666
|
+
if (passwordsDoNotMatch) {
|
|
27667
|
+
$$invalidate(8, message = interpolate('passwordConfirmationError', null, 'Passwords do not match'));
|
|
27668
|
+
} else if (isRequired) {
|
|
27669
|
+
$$invalidate(8, message = interpolate('requiredField', null, 'This field is required'));
|
|
27670
|
+
} else {
|
|
27671
|
+
$$invalidate(8, message = '');
|
|
27672
|
+
}
|
|
27658
27673
|
}
|
|
27659
27674
|
}
|
|
27660
27675
|
};
|
|
27661
27676
|
|
|
27662
27677
|
return [
|
|
27663
27678
|
forceValidityFailure,
|
|
27664
|
-
|
|
27679
|
+
passwordsDoNotMatch,
|
|
27665
27680
|
isRequired,
|
|
27666
27681
|
key,
|
|
27667
27682
|
showMessage,
|
|
27668
27683
|
value,
|
|
27669
27684
|
isVisible,
|
|
27670
27685
|
type,
|
|
27686
|
+
message,
|
|
27671
27687
|
Input,
|
|
27672
27688
|
onChangeWrapper,
|
|
27673
27689
|
toggleVisibility,
|
|
@@ -27685,12 +27701,12 @@ class Confirm_input extends SvelteComponent {
|
|
|
27685
27701
|
|
|
27686
27702
|
init(this, options, instance$q, create_fragment$q, safe_not_equal, {
|
|
27687
27703
|
forceValidityFailure: 0,
|
|
27688
|
-
|
|
27704
|
+
passwordsDoNotMatch: 1,
|
|
27689
27705
|
isRequired: 2,
|
|
27690
27706
|
key: 3,
|
|
27691
|
-
onChange:
|
|
27692
|
-
resetValue:
|
|
27693
|
-
style:
|
|
27707
|
+
onChange: 12,
|
|
27708
|
+
resetValue: 13,
|
|
27709
|
+
style: 14,
|
|
27694
27710
|
showMessage: 4
|
|
27695
27711
|
});
|
|
27696
27712
|
}
|
|
@@ -27846,8 +27862,9 @@ function create_if_block$a(ctx) {
|
|
|
27846
27862
|
confirminput = new Confirm_input({
|
|
27847
27863
|
props: {
|
|
27848
27864
|
forceValidityFailure: /*doPasswordsMatch*/ ctx[9] === false,
|
|
27849
|
-
|
|
27865
|
+
passwordsDoNotMatch: /*doPasswordsMatch*/ ctx[9] === false,
|
|
27850
27866
|
key: /*key*/ ctx[0],
|
|
27867
|
+
isRequired: /*value*/ ctx[7].length > 0,
|
|
27851
27868
|
onChange: /*confirmInput*/ ctx[15],
|
|
27852
27869
|
resetValue: /*resetValue*/ ctx[11],
|
|
27853
27870
|
showMessage: /*doPasswordsMatch*/ ctx[9] === false,
|
|
@@ -27866,8 +27883,9 @@ function create_if_block$a(ctx) {
|
|
|
27866
27883
|
p(ctx, dirty) {
|
|
27867
27884
|
const confirminput_changes = {};
|
|
27868
27885
|
if (dirty & /*doPasswordsMatch*/ 512) confirminput_changes.forceValidityFailure = /*doPasswordsMatch*/ ctx[9] === false;
|
|
27869
|
-
if (dirty & /*doPasswordsMatch*/ 512) confirminput_changes.
|
|
27886
|
+
if (dirty & /*doPasswordsMatch*/ 512) confirminput_changes.passwordsDoNotMatch = /*doPasswordsMatch*/ ctx[9] === false;
|
|
27870
27887
|
if (dirty & /*key*/ 1) confirminput_changes.key = /*key*/ ctx[0];
|
|
27888
|
+
if (dirty & /*value*/ 128) confirminput_changes.isRequired = /*value*/ ctx[7].length > 0;
|
|
27871
27889
|
if (dirty & /*resetValue*/ 2048) confirminput_changes.resetValue = /*resetValue*/ ctx[11];
|
|
27872
27890
|
if (dirty & /*doPasswordsMatch*/ 512) confirminput_changes.showMessage = /*doPasswordsMatch*/ ctx[9] === false;
|
|
27873
27891
|
if (dirty & /*style*/ 16) confirminput_changes.style = /*style*/ ctx[4];
|