@adobe/helix-rum-enhancer 2.31.1 → 2.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [2.33.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.32.0...v2.33.0) (2025-03-24)
2
+
3
+
4
+ ### Features
5
+
6
+ * track all resources loaded on ups.com ([285a495](https://github.com/adobe/helix-rum-enhancer/commit/285a49565b0b96d182cb19923b8e6b93b53c9b00))
7
+
8
+ # [2.32.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.1...v2.32.0) (2025-03-11)
9
+
10
+
11
+ ### Features
12
+
13
+ * bringing back some more checkpoints: search, login and signup ([#372](https://github.com/adobe/helix-rum-enhancer/issues/372)) ([0a3ef75](https://github.com/adobe/helix-rum-enhancer/commit/0a3ef754666355adadf063f7230e9436f5f128ce))
14
+
1
15
  ## [2.31.1](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.0...v2.31.1) (2025-03-11)
2
16
 
3
17
 
package/modules/dom.js CHANGED
@@ -79,7 +79,7 @@ function getSourceElement(el) {
79
79
  : ''));
80
80
  }
81
81
  if (walk(el, isButton)) return 'button';
82
- return el.tagName.toLowerCase().match(/^(a|img|video)$/) && el.tagName.toLowerCase();
82
+ return el.tagName.toLowerCase().match(/^(a|img|video|form)$/) && el.tagName.toLowerCase();
83
83
  }
84
84
 
85
85
  function getSourceIdentifier(el) {
package/modules/fflags.js CHANGED
@@ -19,5 +19,5 @@ export const fflags = {
19
19
  redirect: [620, 1139],
20
20
  example: [543, 770, 1136],
21
21
  language: [543, 959, 1139, 620],
22
- allresources: [1139],
22
+ allresources: [1139, 457],
23
23
  };
package/modules/index.js CHANGED
@@ -43,12 +43,36 @@ const PLUGINS = {
43
43
  // test: broken-plugin
44
44
  };
45
45
 
46
+ function getIntersectionObsever(checkpoint) {
47
+ /* c8 ignore next 3 */
48
+ if (!window.IntersectionObserver) {
49
+ return null;
50
+ }
51
+ const observer = new IntersectionObserver((entries) => {
52
+ try {
53
+ entries
54
+ .filter((e) => e.isIntersecting)
55
+ .forEach((e) => {
56
+ observer.unobserve(e.target); // observe only once
57
+ const target = targetSelector(e.target);
58
+ const source = sourceSelector(e.target);
59
+ sampleRUM(checkpoint, { target, source });
60
+ });
61
+ /* c8 ignore next 3 */
62
+ } catch (error) {
63
+ // something went wrong
64
+ }
65
+ });
66
+ return observer;
67
+ }
68
+
46
69
  const PLUGIN_PARAMETERS = {
47
70
  context: document.body,
48
71
  fflags,
49
72
  sampleRUM,
50
73
  sourceSelector,
51
74
  targetSelector,
75
+ getIntersectionObsever,
52
76
  };
53
77
 
54
78
  const pluginCache = new Map();
@@ -206,28 +230,6 @@ function activateMediaMO() {
206
230
  );
207
231
  }
208
232
 
209
- function getIntersectionObsever(checkpoint) {
210
- /* c8 ignore next 3 */
211
- if (!window.IntersectionObserver) {
212
- return null;
213
- }
214
- const observer = new IntersectionObserver((entries) => {
215
- try {
216
- entries
217
- .filter((e) => e.isIntersecting)
218
- .forEach((e) => {
219
- observer.unobserve(e.target); // observe only once
220
- const target = targetSelector(e.target);
221
- const source = sourceSelector(e.target);
222
- sampleRUM(checkpoint, { target, source });
223
- });
224
- /* c8 ignore next 3 */
225
- } catch (error) {
226
- // something went wrong
227
- }
228
- });
229
- return observer;
230
- }
231
233
  function addViewBlockTracking(element) {
232
234
  const blockobserver = getIntersectionObsever('viewblock');
233
235
  if (blockobserver) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/helix-rum-enhancer",
3
- "version": "2.31.1",
3
+ "version": "2.33.0",
4
4
  "description": "Helix RUM Enhancer",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "devDependencies": {
36
36
  "@adobe/eslint-config-helix": "2.0.9",
37
- "@adobe/helix-rum-js": "2.10.0",
37
+ "@adobe/helix-rum-js": "2.10.1",
38
38
  "@esm-bundle/chai": "4.3.4-fix.0",
39
39
  "@rollup/plugin-babel": "6.0.4",
40
40
  "@semantic-release/changelog": "6.0.3",
@@ -53,10 +53,10 @@
53
53
  "husky": "9.1.7",
54
54
  "jsdoc-to-markdown": "9.1.1",
55
55
  "junit-report-builder": "5.1.1",
56
- "lint-staged": "15.4.3",
56
+ "lint-staged": "15.5.0",
57
57
  "mocha": "11.1.0",
58
58
  "mocha-multi-reporters": "1.5.1",
59
- "rollup": "4.35.0",
59
+ "rollup": "4.36.0",
60
60
  "rollup-plugin-checksum": "1.0.1",
61
61
  "rollup-plugin-eslint-bundle": "9.0.0",
62
62
  "semantic-release": "24.2.3",
package/plugins/form.js CHANGED
@@ -9,11 +9,26 @@
9
9
  * OF ANY KIND, either express or implied. See the License for the specific language
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
+
13
+ export const getSubmitType = (el) => {
14
+ if (!el || el.tagName !== 'FORM') return undefined;
15
+ // if the form has a search role or a search field, it's a search form
16
+ if (el.getAttribute('role') === 'search'
17
+ || el.querySelector('input[type="search"], input[role="searchbox"]')) return 'search';
18
+ // if the form has one password input, it's a login form
19
+ // if the form has more than one password input, it's a signup form
20
+ const pwCount = el.querySelectorAll('input[type="password"]').length;
21
+ if (pwCount === 1) return 'login';
22
+ if (pwCount > 1) return 'signup';
23
+ return 'formsubmit';
24
+ };
25
+
12
26
  export default function addFormTracking({
13
- sampleRUM, sourceSelector, targetSelector, context,
27
+ sampleRUM, sourceSelector, targetSelector, context, getIntersectionObsever,
14
28
  }) {
15
29
  context.querySelectorAll('form').forEach((form) => {
16
- form.addEventListener('submit', (e) => sampleRUM('formsubmit', { target: targetSelector(e.target), source: sourceSelector(e.target) }), { once: true });
30
+ form.addEventListener('submit', (e) => sampleRUM(getSubmitType(e.target), { target: targetSelector(e.target), source: sourceSelector(e.target) }), { once: true });
31
+ getIntersectionObsever('viewblock').observe(form);
17
32
  let lastSource;
18
33
  form.addEventListener('change', (e) => {
19
34
  if (e.target.checkVisibility()) {
package/src/index.js CHANGED
@@ -21,7 +21,7 @@
21
21
  redirect: [620, 1139],
22
22
  example: [543, 770, 1136],
23
23
  language: [543, 959, 1139, 620],
24
- allresources: [1139]
24
+ allresources: [1139, 457]
25
25
  };
26
26
 
27
27
  const KNOWN_PROPERTIES = ['weight', 'id', 'referer', 'checkpoint', 't', 'source', 'target', 'cwv', 'CLS', 'FID', 'LCP', 'INP', 'TTFB'];
@@ -91,7 +91,7 @@
91
91
  return el.tagName.toLowerCase() + (['INPUT', 'BUTTON'].includes(el.tagName) ? `[type='${el.getAttribute('type') || ''}']` : '');
92
92
  }
93
93
  if (walk(el, isButton)) return 'button';
94
- return el.tagName.toLowerCase().match(/^(a|img|video)$/) && el.tagName.toLowerCase();
94
+ return el.tagName.toLowerCase().match(/^(a|img|video|form)$/) && el.tagName.toLowerCase();
95
95
  }
96
96
  function getSourceIdentifier(el) {
97
97
  if (el.id) return `#${el.id}`;
@@ -148,12 +148,32 @@
148
148
  isBlockDependent: true
149
149
  }
150
150
  };
151
+ function getIntersectionObsever(checkpoint) {
152
+ if (!window.IntersectionObserver) {
153
+ return null;
154
+ }
155
+ const observer = new IntersectionObserver(entries => {
156
+ try {
157
+ entries.filter(e => e.isIntersecting).forEach(e => {
158
+ observer.unobserve(e.target);
159
+ const target = targetSelector(e.target);
160
+ const source = sourceSelector(e.target);
161
+ sampleRUM(checkpoint, {
162
+ target,
163
+ source
164
+ });
165
+ });
166
+ } catch (error) {}
167
+ });
168
+ return observer;
169
+ }
151
170
  const PLUGIN_PARAMETERS = {
152
171
  context: document.body,
153
172
  fflags,
154
173
  sampleRUM,
155
174
  sourceSelector,
156
- targetSelector
175
+ targetSelector,
176
+ getIntersectionObsever
157
177
  };
158
178
  const pluginCache = new Map();
159
179
  function loadPlugin(key, params) {
@@ -301,25 +321,6 @@
301
321
  childList: true
302
322
  });
303
323
  }
304
- function getIntersectionObsever(checkpoint) {
305
- if (!window.IntersectionObserver) {
306
- return null;
307
- }
308
- const observer = new IntersectionObserver(entries => {
309
- try {
310
- entries.filter(e => e.isIntersecting).forEach(e => {
311
- observer.unobserve(e.target);
312
- const target = targetSelector(e.target);
313
- const source = sourceSelector(e.target);
314
- sampleRUM(checkpoint, {
315
- target,
316
- source
317
- });
318
- });
319
- } catch (error) {}
320
- });
321
- return observer;
322
- }
323
324
  function addViewBlockTracking(element) {
324
325
  const blockobserver = getIntersectionObsever('viewblock');
325
326
  if (blockobserver) {
package/src/index.md5 CHANGED
@@ -1 +1 @@
1
- 8b85aad6cf2f2b2e97ddd2fed284265b
1
+ aaf6f6e0e4ff60b53769f7deead28f2a
@@ -9,19 +9,29 @@
9
9
  * OF ANY KIND, either express or implied. See the License for the specific language
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
+ const getSubmitType = el => {
13
+ if (!el || el.tagName !== 'FORM') return undefined;
14
+ if (el.getAttribute('role') === 'search' || el.querySelector('input[type="search"], input[role="searchbox"]')) return 'search';
15
+ const pwCount = el.querySelectorAll('input[type="password"]').length;
16
+ if (pwCount === 1) return 'login';
17
+ if (pwCount > 1) return 'signup';
18
+ return 'formsubmit';
19
+ };
12
20
  function addFormTracking({
13
21
  sampleRUM,
14
22
  sourceSelector,
15
23
  targetSelector,
16
- context
24
+ context,
25
+ getIntersectionObsever
17
26
  }) {
18
27
  context.querySelectorAll('form').forEach(form => {
19
- form.addEventListener('submit', e => sampleRUM('formsubmit', {
28
+ form.addEventListener('submit', e => sampleRUM(getSubmitType(e.target), {
20
29
  target: targetSelector(e.target),
21
30
  source: sourceSelector(e.target)
22
31
  }), {
23
32
  once: true
24
33
  });
34
+ getIntersectionObsever('viewblock').observe(form);
25
35
  let lastSource;
26
36
  form.addEventListener('change', e => {
27
37
  if (e.target.checkVisibility()) {
@@ -44,4 +54,4 @@ function addFormTracking({
44
54
  });
45
55
  }
46
56
 
47
- export { addFormTracking as default };
57
+ export { addFormTracking as default, getSubmitType };
@@ -9,19 +9,29 @@
9
9
  * OF ANY KIND, either express or implied. See the License for the specific language
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
+ const getSubmitType = el => {
13
+ if (!el || el.tagName !== 'FORM') return undefined;
14
+ if (el.getAttribute('role') === 'search' || el.querySelector('input[type="search"], input[role="searchbox"]')) return 'search';
15
+ const pwCount = el.querySelectorAll('input[type="password"]').length;
16
+ if (pwCount === 1) return 'login';
17
+ if (pwCount > 1) return 'signup';
18
+ return 'formsubmit';
19
+ };
12
20
  function addFormTracking({
13
21
  sampleRUM,
14
22
  sourceSelector,
15
23
  targetSelector,
16
- context
24
+ context,
25
+ getIntersectionObsever
17
26
  }) {
18
27
  context.querySelectorAll('form').forEach(form => {
19
- form.addEventListener('submit', e => sampleRUM('formsubmit', {
28
+ form.addEventListener('submit', e => sampleRUM(getSubmitType(e.target), {
20
29
  target: targetSelector(e.target),
21
30
  source: sourceSelector(e.target)
22
31
  }), {
23
32
  once: true
24
33
  });
34
+ getIntersectionObsever('viewblock').observe(form);
25
35
  let lastSource;
26
36
  form.addEventListener('change', e => {
27
37
  if (e.target.checkVisibility()) {
@@ -44,5 +54,5 @@ function addFormTracking({
44
54
  });
45
55
  }
46
56
 
47
- export { addFormTracking as default };
48
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybS5tYXAuanMiLCJzb3VyY2VzIjpbIi4uLy4uL3BsdWdpbnMvZm9ybS5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IDIwMjQgQWRvYmUuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiBUaGlzIGZpbGUgaXMgbGljZW5zZWQgdG8geW91IHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuIFlvdSBtYXkgb2J0YWluIGEgY29weVxuICogb2YgdGhlIExpY2Vuc2UgYXQgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZSBkaXN0cmlidXRlZCB1bmRlclxuICogdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLCBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgUkVQUkVTRU5UQVRJT05TXG4gKiBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4gU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2VcbiAqIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGFkZEZvcm1UcmFja2luZyh7XG4gIHNhbXBsZVJVTSwgc291cmNlU2VsZWN0b3IsIHRhcmdldFNlbGVjdG9yLCBjb250ZXh0LFxufSkge1xuICBjb250ZXh0LnF1ZXJ5U2VsZWN0b3JBbGwoJ2Zvcm0nKS5mb3JFYWNoKChmb3JtKSA9PiB7XG4gICAgZm9ybS5hZGRFdmVudExpc3RlbmVyKCdzdWJtaXQnLCAoZSkgPT4gc2FtcGxlUlVNKCdmb3Jtc3VibWl0JywgeyB0YXJnZXQ6IHRhcmdldFNlbGVjdG9yKGUudGFyZ2V0KSwgc291cmNlOiBzb3VyY2VTZWxlY3RvcihlLnRhcmdldCkgfSksIHsgb25jZTogdHJ1ZSB9KTtcbiAgICBsZXQgbGFzdFNvdXJjZTtcbiAgICBmb3JtLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIChlKSA9PiB7XG4gICAgICBpZiAoZS50YXJnZXQuY2hlY2tWaXNpYmlsaXR5KCkpIHtcbiAgICAgICAgY29uc3Qgc291cmNlID0gc291cmNlU2VsZWN0b3IoZS50YXJnZXQpO1xuICAgICAgICBpZiAoc291cmNlICE9PSBsYXN0U291cmNlKSB7XG4gICAgICAgICAgc2FtcGxlUlVNKCdmaWxsJywgeyBzb3VyY2UgfSk7XG4gICAgICAgICAgbGFzdFNvdXJjZSA9IHNvdXJjZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICAgIGZvcm0uYWRkRXZlbnRMaXN0ZW5lcignZm9jdXNpbicsIChlKSA9PiB7XG4gICAgICBpZiAoWydJTlBVVCcsICdURVhUQVJFQScsICdTRUxFQ1QnLCAnQlVUVE9OJ10uaW5jbHVkZXMoZS50YXJnZXQudGFnTmFtZSlcbiAgICAgICAgfHwgZS50YXJnZXQuZ2V0QXR0cmlidXRlKCdjb250ZW50ZWRpdGFibGUnKSA9PT0gJ3RydWUnKSB7XG4gICAgICAgIHNhbXBsZVJVTSgnY2xpY2snLCB7IHNvdXJjZTogc291cmNlU2VsZWN0b3IoZS50YXJnZXQpIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICB9KTtcbn1cbiJdLCJuYW1lcyI6WyJhZGRGb3JtVHJhY2tpbmciLCJzYW1wbGVSVU0iLCJzb3VyY2VTZWxlY3RvciIsInRhcmdldFNlbGVjdG9yIiwiY29udGV4dCIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJmb3JFYWNoIiwiZm9ybSIsImFkZEV2ZW50TGlzdGVuZXIiLCJlIiwidGFyZ2V0Iiwic291cmNlIiwib25jZSIsImxhc3RTb3VyY2UiLCJjaGVja1Zpc2liaWxpdHkiLCJpbmNsdWRlcyIsInRhZ05hbWUiLCJnZXRBdHRyaWJ1dGUiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBV2UsU0FBU0EsZUFBZUEsQ0FBQztFQUN0Q0MsU0FBUztFQUFFQyxjQUFjO0VBQUVDLGNBQWM7QUFBRUMsRUFBQUE7QUFDN0MsQ0FBQyxFQUFFO0VBQ0RBLE9BQU8sQ0FBQ0MsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUNDLE9BQU8sQ0FBRUMsSUFBSSxJQUFLO0lBQ2pEQSxJQUFJLENBQUNDLGdCQUFnQixDQUFDLFFBQVEsRUFBR0MsQ0FBQyxJQUFLUixTQUFTLENBQUMsWUFBWSxFQUFFO0FBQUVTLE1BQUFBLE1BQU0sRUFBRVAsY0FBYyxDQUFDTSxDQUFDLENBQUNDLE1BQU0sQ0FBQztBQUFFQyxNQUFBQSxNQUFNLEVBQUVULGNBQWMsQ0FBQ08sQ0FBQyxDQUFDQyxNQUFNO0FBQUUsS0FBQyxDQUFDLEVBQUU7QUFBRUUsTUFBQUEsSUFBSSxFQUFFO0FBQUssS0FBQyxDQUFDO0FBQ3ZKLElBQUEsSUFBSUMsVUFBVTtBQUNkTixJQUFBQSxJQUFJLENBQUNDLGdCQUFnQixDQUFDLFFBQVEsRUFBR0MsQ0FBQyxJQUFLO0FBQ3JDLE1BQUEsSUFBSUEsQ0FBQyxDQUFDQyxNQUFNLENBQUNJLGVBQWUsRUFBRSxFQUFFO0FBQzlCLFFBQUEsTUFBTUgsTUFBTSxHQUFHVCxjQUFjLENBQUNPLENBQUMsQ0FBQ0MsTUFBTSxDQUFDO1FBQ3ZDLElBQUlDLE1BQU0sS0FBS0UsVUFBVSxFQUFFO1VBQ3pCWixTQUFTLENBQUMsTUFBTSxFQUFFO0FBQUVVLFlBQUFBO0FBQU8sV0FBQyxDQUFDO0FBQzdCRSxVQUFBQSxVQUFVLEdBQUdGLE1BQU07QUFDckI7QUFDRjtBQUNGLEtBQUMsQ0FBQztBQUNGSixJQUFBQSxJQUFJLENBQUNDLGdCQUFnQixDQUFDLFNBQVMsRUFBR0MsQ0FBQyxJQUFLO0FBQ3RDLE1BQUEsSUFBSSxDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDTSxRQUFRLENBQUNOLENBQUMsQ0FBQ0MsTUFBTSxDQUFDTSxPQUFPLENBQUMsSUFDbkVQLENBQUMsQ0FBQ0MsTUFBTSxDQUFDTyxZQUFZLENBQUMsaUJBQWlCLENBQUMsS0FBSyxNQUFNLEVBQUU7UUFDeERoQixTQUFTLENBQUMsT0FBTyxFQUFFO0FBQUVVLFVBQUFBLE1BQU0sRUFBRVQsY0FBYyxDQUFDTyxDQUFDLENBQUNDLE1BQU07QUFBRSxTQUFDLENBQUM7QUFDMUQ7QUFDRixLQUFDLENBQUM7QUFDSixHQUFDLENBQUM7QUFDSjs7OzsifQ==
57
+ export { addFormTracking as default, getSubmitType };
58
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybS5tYXAuanMiLCJzb3VyY2VzIjpbIi4uLy4uL3BsdWdpbnMvZm9ybS5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IDIwMjQgQWRvYmUuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiBUaGlzIGZpbGUgaXMgbGljZW5zZWQgdG8geW91IHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuIFlvdSBtYXkgb2J0YWluIGEgY29weVxuICogb2YgdGhlIExpY2Vuc2UgYXQgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZSBkaXN0cmlidXRlZCB1bmRlclxuICogdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLCBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgUkVQUkVTRU5UQVRJT05TXG4gKiBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4gU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2VcbiAqIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuZXhwb3J0IGNvbnN0IGdldFN1Ym1pdFR5cGUgPSAoZWwpID0+IHtcbiAgaWYgKCFlbCB8fCBlbC50YWdOYW1lICE9PSAnRk9STScpIHJldHVybiB1bmRlZmluZWQ7XG4gIC8vIGlmIHRoZSBmb3JtIGhhcyBhIHNlYXJjaCByb2xlIG9yIGEgc2VhcmNoIGZpZWxkLCBpdCdzIGEgc2VhcmNoIGZvcm1cbiAgaWYgKGVsLmdldEF0dHJpYnV0ZSgncm9sZScpID09PSAnc2VhcmNoJ1xuICAgIHx8IGVsLnF1ZXJ5U2VsZWN0b3IoJ2lucHV0W3R5cGU9XCJzZWFyY2hcIl0sIGlucHV0W3JvbGU9XCJzZWFyY2hib3hcIl0nKSkgcmV0dXJuICdzZWFyY2gnO1xuICAvLyBpZiB0aGUgZm9ybSBoYXMgb25lIHBhc3N3b3JkIGlucHV0LCBpdCdzIGEgbG9naW4gZm9ybVxuICAvLyBpZiB0aGUgZm9ybSBoYXMgbW9yZSB0aGFuIG9uZSBwYXNzd29yZCBpbnB1dCwgaXQncyBhIHNpZ251cCBmb3JtXG4gIGNvbnN0IHB3Q291bnQgPSBlbC5xdWVyeVNlbGVjdG9yQWxsKCdpbnB1dFt0eXBlPVwicGFzc3dvcmRcIl0nKS5sZW5ndGg7XG4gIGlmIChwd0NvdW50ID09PSAxKSByZXR1cm4gJ2xvZ2luJztcbiAgaWYgKHB3Q291bnQgPiAxKSByZXR1cm4gJ3NpZ251cCc7XG4gIHJldHVybiAnZm9ybXN1Ym1pdCc7XG59O1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBhZGRGb3JtVHJhY2tpbmcoe1xuICBzYW1wbGVSVU0sIHNvdXJjZVNlbGVjdG9yLCB0YXJnZXRTZWxlY3RvciwgY29udGV4dCwgZ2V0SW50ZXJzZWN0aW9uT2JzZXZlcixcbn0pIHtcbiAgY29udGV4dC5xdWVyeVNlbGVjdG9yQWxsKCdmb3JtJykuZm9yRWFjaCgoZm9ybSkgPT4ge1xuICAgIGZvcm0uYWRkRXZlbnRMaXN0ZW5lcignc3VibWl0JywgKGUpID0+IHNhbXBsZVJVTShnZXRTdWJtaXRUeXBlKGUudGFyZ2V0KSwgeyB0YXJnZXQ6IHRhcmdldFNlbGVjdG9yKGUudGFyZ2V0KSwgc291cmNlOiBzb3VyY2VTZWxlY3RvcihlLnRhcmdldCkgfSksIHsgb25jZTogdHJ1ZSB9KTtcbiAgICBnZXRJbnRlcnNlY3Rpb25PYnNldmVyKCd2aWV3YmxvY2snKS5vYnNlcnZlKGZvcm0pO1xuICAgIGxldCBsYXN0U291cmNlO1xuICAgIGZvcm0uYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgKGUpID0+IHtcbiAgICAgIGlmIChlLnRhcmdldC5jaGVja1Zpc2liaWxpdHkoKSkge1xuICAgICAgICBjb25zdCBzb3VyY2UgPSBzb3VyY2VTZWxlY3RvcihlLnRhcmdldCk7XG4gICAgICAgIGlmIChzb3VyY2UgIT09IGxhc3RTb3VyY2UpIHtcbiAgICAgICAgICBzYW1wbGVSVU0oJ2ZpbGwnLCB7IHNvdXJjZSB9KTtcbiAgICAgICAgICBsYXN0U291cmNlID0gc291cmNlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gICAgZm9ybS5hZGRFdmVudExpc3RlbmVyKCdmb2N1c2luJywgKGUpID0+IHtcbiAgICAgIGlmIChbJ0lOUFVUJywgJ1RFWFRBUkVBJywgJ1NFTEVDVCcsICdCVVRUT04nXS5pbmNsdWRlcyhlLnRhcmdldC50YWdOYW1lKVxuICAgICAgICB8fCBlLnRhcmdldC5nZXRBdHRyaWJ1dGUoJ2NvbnRlbnRlZGl0YWJsZScpID09PSAndHJ1ZScpIHtcbiAgICAgICAgc2FtcGxlUlVNKCdjbGljaycsIHsgc291cmNlOiBzb3VyY2VTZWxlY3RvcihlLnRhcmdldCkgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH0pO1xufVxuIl0sIm5hbWVzIjpbImdldFN1Ym1pdFR5cGUiLCJlbCIsInRhZ05hbWUiLCJ1bmRlZmluZWQiLCJnZXRBdHRyaWJ1dGUiLCJxdWVyeVNlbGVjdG9yIiwicHdDb3VudCIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJsZW5ndGgiLCJhZGRGb3JtVHJhY2tpbmciLCJzYW1wbGVSVU0iLCJzb3VyY2VTZWxlY3RvciIsInRhcmdldFNlbGVjdG9yIiwiY29udGV4dCIsImdldEludGVyc2VjdGlvbk9ic2V2ZXIiLCJmb3JFYWNoIiwiZm9ybSIsImFkZEV2ZW50TGlzdGVuZXIiLCJlIiwidGFyZ2V0Iiwic291cmNlIiwib25jZSIsIm9ic2VydmUiLCJsYXN0U291cmNlIiwiY2hlY2tWaXNpYmlsaXR5IiwiaW5jbHVkZXMiXSwibWFwcGluZ3MiOiI7Ozs7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
@@ -1 +1 @@
1
- e5aafcb0c1551f984c0b69176cd839d8
1
+ ddb71d9833428d7000bea86d3f3bc7e2
@@ -1 +1 @@
1
- 517639c5549d69645ca8d34d41e99914
1
+ 5335d59147580bf5f51b609e1ce676b3