@okeyamy/lua 5.0.4

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.
@@ -0,0 +1,304 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * UTM Parameter Extraction & Context Detection
5
+ * Uses native URLSearchParams API for extracting UTM parameters
6
+ * and document.referrer/navigator.userAgent for context inference
7
+ *
8
+ * No ES6 imports - self-contained IIFE that registers on window.LuaUTM
9
+ * Can be loaded standalone via <script> tag or bundled by Rollup
10
+ */
11
+ ;
12
+ (function (root) {
13
+ 'use strict';
14
+
15
+ // Default timeout for async operations (1 second max as recommended)
16
+ var UTM_TIMEOUT_MS = 1000;
17
+
18
+ // Allowed UTM parameter names
19
+ var UTM_PARAMS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
20
+
21
+ // Referrer type patterns
22
+ var REFERRER_PATTERNS = {
23
+ google: /google\./i,
24
+ bing: /bing\./i,
25
+ yahoo: /yahoo\./i,
26
+ duckduckgo: /duckduckgo\./i,
27
+ facebook: /facebook\.com|fb\.com/i,
28
+ twitter: /twitter\.com|t\.co|x\.com/i,
29
+ instagram: /instagram\.com/i,
30
+ linkedin: /linkedin\.com/i,
31
+ pinterest: /pinterest\./i,
32
+ tiktok: /tiktok\.com/i,
33
+ youtube: /youtube\.com|youtu\.be/i,
34
+ reddit: /reddit\.com/i
35
+ };
36
+
37
+ // Referrer category mapping
38
+ var REFERRER_CATEGORIES = {
39
+ search: ['google', 'bing', 'yahoo', 'duckduckgo'],
40
+ social: ['facebook', 'twitter', 'instagram', 'linkedin', 'pinterest', 'tiktok', 'youtube', 'reddit']
41
+ };
42
+
43
+ /**
44
+ * Safely extracts UTM parameters from URL using native URLSearchParams API
45
+ * @param {string} [url] - URL to parse (defaults to window.location.search)
46
+ * @returns {Object} - Object containing UTM parameters
47
+ */
48
+ function extractUTMParams(url) {
49
+ var result = {};
50
+ try {
51
+ var searchString = url || (typeof window !== 'undefined' ? window.location.search : '');
52
+ if (!searchString) {
53
+ return result;
54
+ }
55
+
56
+ // Use native URLSearchParams API
57
+ var params = new URLSearchParams(searchString);
58
+ UTM_PARAMS.forEach(function (param) {
59
+ var value = params.get(param);
60
+ if (value) {
61
+ // Sanitize: only allow alphanumeric, dashes, underscores
62
+ result[param] = sanitizeParam(value);
63
+ }
64
+ });
65
+ } catch (e) {
66
+ // Fallback: return empty object on any error
67
+ console.warn('[Lua UTM] Error extracting UTM params:', e);
68
+ }
69
+ return result;
70
+ }
71
+
72
+ /**
73
+ * Sanitize parameter value to prevent XSS
74
+ * Only allows alphanumeric, dashes, underscores, and spaces
75
+ * @param {string} value - Raw parameter value
76
+ * @returns {string} - Sanitized value
77
+ */
78
+ function sanitizeParam(value) {
79
+ if (typeof value !== 'string') return '';
80
+ // Remove any HTML tags and special characters
81
+ return value.replace(/<[^>]*>/g, '') // Remove HTML tags
82
+ .replace(/[^\w\s\-_.]/g, '') // Only allow safe characters
83
+ .substring(0, 100) // Limit length
84
+ .trim();
85
+ }
86
+
87
+ /**
88
+ * Detect referrer type from document.referrer
89
+ * @returns {Object} - { source: string, category: 'search'|'social'|'email'|'direct'|'other' }
90
+ */
91
+ function detectReferrer() {
92
+ var result = {
93
+ source: 'direct',
94
+ category: 'direct',
95
+ url: ''
96
+ };
97
+ try {
98
+ if (typeof document === 'undefined' || !document.referrer) {
99
+ return result;
100
+ }
101
+ result.url = document.referrer;
102
+
103
+ // Check for email patterns in referrer
104
+ if (/mail\.|email\.|newsletter/i.test(document.referrer)) {
105
+ result.source = 'email';
106
+ result.category = 'email';
107
+ return result;
108
+ }
109
+
110
+ // Check against known patterns
111
+ for (var source in REFERRER_PATTERNS) {
112
+ if (REFERRER_PATTERNS[source].test(document.referrer)) {
113
+ result.source = source;
114
+
115
+ // Determine category
116
+ for (var category in REFERRER_CATEGORIES) {
117
+ if (REFERRER_CATEGORIES[category].indexOf(source) !== -1) {
118
+ result.category = category;
119
+ break;
120
+ }
121
+ }
122
+ return result;
123
+ }
124
+ }
125
+
126
+ // Unknown external referrer
127
+ result.source = 'external';
128
+ result.category = 'other';
129
+ } catch (e) {
130
+ console.warn('[Lua UTM] Error detecting referrer:', e);
131
+ }
132
+ return result;
133
+ }
134
+
135
+ /**
136
+ * Get user agent info (for device/browser detection)
137
+ * @returns {Object} - User agent metadata
138
+ */
139
+ function getUserAgentInfo() {
140
+ var result = {
141
+ raw: '',
142
+ isMobile: false,
143
+ isTablet: false,
144
+ isDesktop: true
145
+ };
146
+ try {
147
+ if (typeof navigator === 'undefined' || !navigator.userAgent) {
148
+ return result;
149
+ }
150
+ result.raw = navigator.userAgent;
151
+
152
+ // Mobile detection
153
+ result.isMobile = /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
154
+ result.isTablet = /iPad|Android(?!.*Mobile)/i.test(navigator.userAgent);
155
+ result.isDesktop = !result.isMobile && !result.isTablet;
156
+ } catch (e) {
157
+ console.warn('[Lua UTM] Error getting user agent:', e);
158
+ }
159
+ return result;
160
+ }
161
+
162
+ /**
163
+ * Get full personalization context
164
+ * Combines UTM params, referrer info, and user agent
165
+ * @param {Object} [options] - Configuration options
166
+ * @param {string} [options.url] - Custom URL to parse
167
+ * @returns {Object} - Complete context object
168
+ */
169
+ function getContext(options) {
170
+ options = options || {};
171
+ var context = {
172
+ utm: extractUTMParams(options.url),
173
+ referrer: detectReferrer(),
174
+ userAgent: getUserAgentInfo(),
175
+ timestamp: Date.now(),
176
+ hasUTM: false,
177
+ primaryIntent: 'unknown'
178
+ };
179
+
180
+ // Determine if we have UTM data
181
+ context.hasUTM = Object.keys(context.utm).length > 0;
182
+
183
+ // Infer primary intent
184
+ context.primaryIntent = inferIntent(context);
185
+ return context;
186
+ }
187
+
188
+ /**
189
+ * Infer user intent from context
190
+ * Priority: UTM campaign > UTM source > Referrer category
191
+ * @param {Object} context - Full context object
192
+ * @returns {string} - Inferred intent key
193
+ */
194
+ function inferIntent(context) {
195
+ // Priority 1: UTM campaign tells us the specific intent
196
+ if (context.utm.utm_campaign) {
197
+ var campaign = context.utm.utm_campaign.toLowerCase();
198
+ if (/sale|discount|offer|promo/i.test(campaign)) return 'price-focused';
199
+ if (/gaming|game|esport/i.test(campaign)) return 'gaming';
200
+ if (/work|office|professional|productivity/i.test(campaign)) return 'professional';
201
+ if (/creative|design|art|studio/i.test(campaign)) return 'creative';
202
+ if (/brand|story|about/i.test(campaign)) return 'brand-story';
203
+ }
204
+
205
+ // Priority 2: UTM source can indicate intent
206
+ if (context.utm.utm_source) {
207
+ var source = context.utm.utm_source.toLowerCase();
208
+ if (/google|bing|yahoo/i.test(source)) return 'search-optimized';
209
+ if (/facebook|instagram|tiktok/i.test(source)) return 'social-visual';
210
+ if (/twitter|x$/i.test(source)) return 'social-brief';
211
+ if (/email|newsletter/i.test(source)) return 'returning-user';
212
+ if (/youtube/i.test(source)) return 'video-engaged';
213
+ }
214
+
215
+ // Priority 3: Referrer category
216
+ if (context.referrer.category === 'search') return 'search-optimized';
217
+ if (context.referrer.category === 'social') return 'social-visual';
218
+ if (context.referrer.category === 'email') return 'returning-user';
219
+
220
+ // Default
221
+ return 'default';
222
+ }
223
+
224
+ /**
225
+ * Get context with timeout fallback
226
+ * Returns default context if operation takes too long
227
+ * @param {Object} [options] - Configuration options
228
+ * @param {number} [options.timeout] - Timeout in ms (default: 1000)
229
+ * @returns {Promise<Object>} - Context object
230
+ */
231
+ function getContextAsync(options) {
232
+ options = options || {};
233
+ var timeout = options.timeout || UTM_TIMEOUT_MS;
234
+ return new Promise(function (resolve) {
235
+ var timer = setTimeout(function () {
236
+ // Timeout: return default context
237
+ resolve({
238
+ utm: {},
239
+ referrer: {
240
+ source: 'direct',
241
+ category: 'direct',
242
+ url: ''
243
+ },
244
+ userAgent: {
245
+ raw: '',
246
+ isMobile: false,
247
+ isTablet: false,
248
+ isDesktop: true
249
+ },
250
+ timestamp: Date.now(),
251
+ hasUTM: false,
252
+ primaryIntent: 'default',
253
+ timedOut: true
254
+ });
255
+ }, timeout);
256
+ try {
257
+ var context = getContext(options);
258
+ clearTimeout(timer);
259
+ context.timedOut = false;
260
+ resolve(context);
261
+ } catch (e) {
262
+ clearTimeout(timer);
263
+ resolve({
264
+ utm: {},
265
+ referrer: {
266
+ source: 'direct',
267
+ category: 'direct',
268
+ url: ''
269
+ },
270
+ userAgent: {
271
+ raw: '',
272
+ isMobile: false,
273
+ isTablet: false,
274
+ isDesktop: true
275
+ },
276
+ timestamp: Date.now(),
277
+ hasUTM: false,
278
+ primaryIntent: 'default',
279
+ error: e.message
280
+ });
281
+ }
282
+ });
283
+ }
284
+
285
+ // --- Public API ---
286
+ // Register on the global root (window in browser)
287
+ var LuaUTM = {
288
+ extractUTMParams: extractUTMParams,
289
+ sanitizeParam: sanitizeParam,
290
+ detectReferrer: detectReferrer,
291
+ getUserAgentInfo: getUserAgentInfo,
292
+ getContext: getContext,
293
+ getContextAsync: getContextAsync,
294
+ inferIntent: inferIntent,
295
+ UTM_PARAMS: UTM_PARAMS,
296
+ UTM_TIMEOUT_MS: UTM_TIMEOUT_MS,
297
+ REFERRER_PATTERNS: REFERRER_PATTERNS,
298
+ REFERRER_CATEGORIES: REFERRER_CATEGORIES
299
+ };
300
+
301
+ // Expose globally
302
+ root.LuaUTM = LuaUTM;
303
+ })(typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : void 0);
304
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJyb290IiwiVVRNX1RJTUVPVVRfTVMiLCJVVE1fUEFSQU1TIiwiUkVGRVJSRVJfUEFUVEVSTlMiLCJnb29nbGUiLCJiaW5nIiwieWFob28iLCJkdWNrZHVja2dvIiwiZmFjZWJvb2siLCJ0d2l0dGVyIiwiaW5zdGFncmFtIiwibGlua2VkaW4iLCJwaW50ZXJlc3QiLCJ0aWt0b2siLCJ5b3V0dWJlIiwicmVkZGl0IiwiUkVGRVJSRVJfQ0FURUdPUklFUyIsInNlYXJjaCIsInNvY2lhbCIsImV4dHJhY3RVVE1QYXJhbXMiLCJ1cmwiLCJyZXN1bHQiLCJzZWFyY2hTdHJpbmciLCJ3aW5kb3ciLCJsb2NhdGlvbiIsInBhcmFtcyIsIlVSTFNlYXJjaFBhcmFtcyIsImZvckVhY2giLCJwYXJhbSIsInZhbHVlIiwiZ2V0Iiwic2FuaXRpemVQYXJhbSIsImUiLCJjb25zb2xlIiwid2FybiIsInJlcGxhY2UiLCJzdWJzdHJpbmciLCJ0cmltIiwiZGV0ZWN0UmVmZXJyZXIiLCJzb3VyY2UiLCJjYXRlZ29yeSIsImRvY3VtZW50IiwicmVmZXJyZXIiLCJ0ZXN0IiwiaW5kZXhPZiIsImdldFVzZXJBZ2VudEluZm8iLCJyYXciLCJpc01vYmlsZSIsImlzVGFibGV0IiwiaXNEZXNrdG9wIiwibmF2aWdhdG9yIiwidXNlckFnZW50IiwiZ2V0Q29udGV4dCIsIm9wdGlvbnMiLCJjb250ZXh0IiwidXRtIiwidGltZXN0YW1wIiwiRGF0ZSIsIm5vdyIsImhhc1VUTSIsInByaW1hcnlJbnRlbnQiLCJPYmplY3QiLCJrZXlzIiwibGVuZ3RoIiwiaW5mZXJJbnRlbnQiLCJ1dG1fY2FtcGFpZ24iLCJjYW1wYWlnbiIsInRvTG93ZXJDYXNlIiwidXRtX3NvdXJjZSIsImdldENvbnRleHRBc3luYyIsInRpbWVvdXQiLCJQcm9taXNlIiwicmVzb2x2ZSIsInRpbWVyIiwic2V0VGltZW91dCIsInRpbWVkT3V0IiwiY2xlYXJUaW1lb3V0IiwiZXJyb3IiLCJtZXNzYWdlIiwiTHVhVVRNIiwiZ2xvYmFsIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0bS5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJcbi8qKlxuICogVVRNIFBhcmFtZXRlciBFeHRyYWN0aW9uICYgQ29udGV4dCBEZXRlY3Rpb25cbiAqIFVzZXMgbmF0aXZlIFVSTFNlYXJjaFBhcmFtcyBBUEkgZm9yIGV4dHJhY3RpbmcgVVRNIHBhcmFtZXRlcnNcbiAqIGFuZCBkb2N1bWVudC5yZWZlcnJlci9uYXZpZ2F0b3IudXNlckFnZW50IGZvciBjb250ZXh0IGluZmVyZW5jZVxuICpcbiAqIE5vIEVTNiBpbXBvcnRzIC0gc2VsZi1jb250YWluZWQgSUlGRSB0aGF0IHJlZ2lzdGVycyBvbiB3aW5kb3cuTHVhVVRNXG4gKiBDYW4gYmUgbG9hZGVkIHN0YW5kYWxvbmUgdmlhIDxzY3JpcHQ+IHRhZyBvciBidW5kbGVkIGJ5IFJvbGx1cFxuICovXG47KGZ1bmN0aW9uIChyb290KSB7XG4gICAgJ3VzZSBzdHJpY3QnXG5cbiAgICAvLyBEZWZhdWx0IHRpbWVvdXQgZm9yIGFzeW5jIG9wZXJhdGlvbnMgKDEgc2Vjb25kIG1heCBhcyByZWNvbW1lbmRlZClcbiAgICB2YXIgVVRNX1RJTUVPVVRfTVMgPSAxMDAwXG5cbiAgICAvLyBBbGxvd2VkIFVUTSBwYXJhbWV0ZXIgbmFtZXNcbiAgICB2YXIgVVRNX1BBUkFNUyA9IFsndXRtX3NvdXJjZScsICd1dG1fbWVkaXVtJywgJ3V0bV9jYW1wYWlnbicsICd1dG1fY29udGVudCcsICd1dG1fdGVybSddXG5cbiAgICAvLyBSZWZlcnJlciB0eXBlIHBhdHRlcm5zXG4gICAgdmFyIFJFRkVSUkVSX1BBVFRFUk5TID0ge1xuICAgICAgICBnb29nbGU6IC9nb29nbGVcXC4vaSxcbiAgICAgICAgYmluZzogL2JpbmdcXC4vaSxcbiAgICAgICAgeWFob286IC95YWhvb1xcLi9pLFxuICAgICAgICBkdWNrZHVja2dvOiAvZHVja2R1Y2tnb1xcLi9pLFxuICAgICAgICBmYWNlYm9vazogL2ZhY2Vib29rXFwuY29tfGZiXFwuY29tL2ksXG4gICAgICAgIHR3aXR0ZXI6IC90d2l0dGVyXFwuY29tfHRcXC5jb3x4XFwuY29tL2ksXG4gICAgICAgIGluc3RhZ3JhbTogL2luc3RhZ3JhbVxcLmNvbS9pLFxuICAgICAgICBsaW5rZWRpbjogL2xpbmtlZGluXFwuY29tL2ksXG4gICAgICAgIHBpbnRlcmVzdDogL3BpbnRlcmVzdFxcLi9pLFxuICAgICAgICB0aWt0b2s6IC90aWt0b2tcXC5jb20vaSxcbiAgICAgICAgeW91dHViZTogL3lvdXR1YmVcXC5jb218eW91dHVcXC5iZS9pLFxuICAgICAgICByZWRkaXQ6IC9yZWRkaXRcXC5jb20vaVxuICAgIH1cblxuICAgIC8vIFJlZmVycmVyIGNhdGVnb3J5IG1hcHBpbmdcbiAgICB2YXIgUkVGRVJSRVJfQ0FURUdPUklFUyA9IHtcbiAgICAgICAgc2VhcmNoOiBbJ2dvb2dsZScsICdiaW5nJywgJ3lhaG9vJywgJ2R1Y2tkdWNrZ28nXSxcbiAgICAgICAgc29jaWFsOiBbJ2ZhY2Vib29rJywgJ3R3aXR0ZXInLCAnaW5zdGFncmFtJywgJ2xpbmtlZGluJywgJ3BpbnRlcmVzdCcsICd0aWt0b2snLCAneW91dHViZScsICdyZWRkaXQnXVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNhZmVseSBleHRyYWN0cyBVVE0gcGFyYW1ldGVycyBmcm9tIFVSTCB1c2luZyBuYXRpdmUgVVJMU2VhcmNoUGFyYW1zIEFQSVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbdXJsXSAtIFVSTCB0byBwYXJzZSAoZGVmYXVsdHMgdG8gd2luZG93LmxvY2F0aW9uLnNlYXJjaClcbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSAtIE9iamVjdCBjb250YWluaW5nIFVUTSBwYXJhbWV0ZXJzXG4gICAgICovXG4gICAgZnVuY3Rpb24gZXh0cmFjdFVUTVBhcmFtcyh1cmwpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IHt9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHZhciBzZWFyY2hTdHJpbmcgPSB1cmwgfHwgKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnID8gd2luZG93LmxvY2F0aW9uLnNlYXJjaCA6ICcnKVxuXG4gICAgICAgICAgICBpZiAoIXNlYXJjaFN0cmluZykge1xuICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHRcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gVXNlIG5hdGl2ZSBVUkxTZWFyY2hQYXJhbXMgQVBJXG4gICAgICAgICAgICB2YXIgcGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyhzZWFyY2hTdHJpbmcpXG5cbiAgICAgICAgICAgIFVUTV9QQVJBTVMuZm9yRWFjaChmdW5jdGlvbiAocGFyYW0pIHtcbiAgICAgICAgICAgICAgICB2YXIgdmFsdWUgPSBwYXJhbXMuZ2V0KHBhcmFtKVxuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTYW5pdGl6ZTogb25seSBhbGxvdyBhbHBoYW51bWVyaWMsIGRhc2hlcywgdW5kZXJzY29yZXNcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0W3BhcmFtXSA9IHNhbml0aXplUGFyYW0odmFsdWUpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgLy8gRmFsbGJhY2s6IHJldHVybiBlbXB0eSBvYmplY3Qgb24gYW55IGVycm9yXG4gICAgICAgICAgICBjb25zb2xlLndhcm4oJ1tMdWEgVVRNXSBFcnJvciBleHRyYWN0aW5nIFVUTSBwYXJhbXM6JywgZSlcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXN1bHRcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTYW5pdGl6ZSBwYXJhbWV0ZXIgdmFsdWUgdG8gcHJldmVudCBYU1NcbiAgICAgKiBPbmx5IGFsbG93cyBhbHBoYW51bWVyaWMsIGRhc2hlcywgdW5kZXJzY29yZXMsIGFuZCBzcGFjZXNcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdmFsdWUgLSBSYXcgcGFyYW1ldGVyIHZhbHVlXG4gICAgICogQHJldHVybnMge3N0cmluZ30gLSBTYW5pdGl6ZWQgdmFsdWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBzYW5pdGl6ZVBhcmFtKHZhbHVlKSB7XG4gICAgICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnKSByZXR1cm4gJydcbiAgICAgICAgLy8gUmVtb3ZlIGFueSBIVE1MIHRhZ3MgYW5kIHNwZWNpYWwgY2hhcmFjdGVyc1xuICAgICAgICByZXR1cm4gdmFsdWVcbiAgICAgICAgICAgIC5yZXBsYWNlKC88W14+XSo+L2csICcnKSAvLyBSZW1vdmUgSFRNTCB0YWdzXG4gICAgICAgICAgICAucmVwbGFjZSgvW15cXHdcXHNcXC1fLl0vZywgJycpIC8vIE9ubHkgYWxsb3cgc2FmZSBjaGFyYWN0ZXJzXG4gICAgICAgICAgICAuc3Vic3RyaW5nKDAsIDEwMCkgLy8gTGltaXQgbGVuZ3RoXG4gICAgICAgICAgICAudHJpbSgpXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGV0ZWN0IHJlZmVycmVyIHR5cGUgZnJvbSBkb2N1bWVudC5yZWZlcnJlclxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IC0geyBzb3VyY2U6IHN0cmluZywgY2F0ZWdvcnk6ICdzZWFyY2gnfCdzb2NpYWwnfCdlbWFpbCd8J2RpcmVjdCd8J290aGVyJyB9XG4gICAgICovXG4gICAgZnVuY3Rpb24gZGV0ZWN0UmVmZXJyZXIoKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSB7XG4gICAgICAgICAgICBzb3VyY2U6ICdkaXJlY3QnLFxuICAgICAgICAgICAgY2F0ZWdvcnk6ICdkaXJlY3QnLFxuICAgICAgICAgICAgdXJsOiAnJ1xuICAgICAgICB9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgZG9jdW1lbnQgPT09ICd1bmRlZmluZWQnIHx8ICFkb2N1bWVudC5yZWZlcnJlcikge1xuICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHRcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmVzdWx0LnVybCA9IGRvY3VtZW50LnJlZmVycmVyXG5cbiAgICAgICAgICAgIC8vIENoZWNrIGZvciBlbWFpbCBwYXR0ZXJucyBpbiByZWZlcnJlclxuICAgICAgICAgICAgaWYgKC9tYWlsXFwufGVtYWlsXFwufG5ld3NsZXR0ZXIvaS50ZXN0KGRvY3VtZW50LnJlZmVycmVyKSkge1xuICAgICAgICAgICAgICAgIHJlc3VsdC5zb3VyY2UgPSAnZW1haWwnXG4gICAgICAgICAgICAgICAgcmVzdWx0LmNhdGVnb3J5ID0gJ2VtYWlsJ1xuICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHRcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ2hlY2sgYWdhaW5zdCBrbm93biBwYXR0ZXJuc1xuICAgICAgICAgICAgZm9yICh2YXIgc291cmNlIGluIFJFRkVSUkVSX1BBVFRFUk5TKSB7XG4gICAgICAgICAgICAgICAgaWYgKFJFRkVSUkVSX1BBVFRFUk5TW3NvdXJjZV0udGVzdChkb2N1bWVudC5yZWZlcnJlcikpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnNvdXJjZSA9IHNvdXJjZVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIERldGVybWluZSBjYXRlZ29yeVxuICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBjYXRlZ29yeSBpbiBSRUZFUlJFUl9DQVRFR09SSUVTKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoUkVGRVJSRVJfQ0FURUdPUklFU1tjYXRlZ29yeV0uaW5kZXhPZihzb3VyY2UpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5jYXRlZ29yeSA9IGNhdGVnb3J5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHRcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFVua25vd24gZXh0ZXJuYWwgcmVmZXJyZXJcbiAgICAgICAgICAgIHJlc3VsdC5zb3VyY2UgPSAnZXh0ZXJuYWwnXG4gICAgICAgICAgICByZXN1bHQuY2F0ZWdvcnkgPSAnb3RoZXInXG5cbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKCdbTHVhIFVUTV0gRXJyb3IgZGV0ZWN0aW5nIHJlZmVycmVyOicsIGUpXG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzdWx0XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHVzZXIgYWdlbnQgaW5mbyAoZm9yIGRldmljZS9icm93c2VyIGRldGVjdGlvbilcbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSAtIFVzZXIgYWdlbnQgbWV0YWRhdGFcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBnZXRVc2VyQWdlbnRJbmZvKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0ge1xuICAgICAgICAgICAgcmF3OiAnJyxcbiAgICAgICAgICAgIGlzTW9iaWxlOiBmYWxzZSxcbiAgICAgICAgICAgIGlzVGFibGV0OiBmYWxzZSxcbiAgICAgICAgICAgIGlzRGVza3RvcDogdHJ1ZVxuICAgICAgICB9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgbmF2aWdhdG9yID09PSAndW5kZWZpbmVkJyB8fCAhbmF2aWdhdG9yLnVzZXJBZ2VudCkge1xuICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHRcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmVzdWx0LnJhdyA9IG5hdmlnYXRvci51c2VyQWdlbnRcblxuICAgICAgICAgICAgLy8gTW9iaWxlIGRldGVjdGlvblxuICAgICAgICAgICAgcmVzdWx0LmlzTW9iaWxlID0gL0FuZHJvaWR8d2ViT1N8aVBob25lfGlQb2R8QmxhY2tCZXJyeXxJRU1vYmlsZXxPcGVyYSBNaW5pL2kudGVzdChuYXZpZ2F0b3IudXNlckFnZW50KVxuICAgICAgICAgICAgcmVzdWx0LmlzVGFibGV0ID0gL2lQYWR8QW5kcm9pZCg/IS4qTW9iaWxlKS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudClcbiAgICAgICAgICAgIHJlc3VsdC5pc0Rlc2t0b3AgPSAhcmVzdWx0LmlzTW9iaWxlICYmICFyZXN1bHQuaXNUYWJsZXRcblxuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oJ1tMdWEgVVRNXSBFcnJvciBnZXR0aW5nIHVzZXIgYWdlbnQ6JywgZSlcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXN1bHRcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgZnVsbCBwZXJzb25hbGl6YXRpb24gY29udGV4dFxuICAgICAqIENvbWJpbmVzIFVUTSBwYXJhbXMsIHJlZmVycmVyIGluZm8sIGFuZCB1c2VyIGFnZW50XG4gICAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zXSAtIENvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0aW9ucy51cmxdIC0gQ3VzdG9tIFVSTCB0byBwYXJzZVxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IC0gQ29tcGxldGUgY29udGV4dCBvYmplY3RcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBnZXRDb250ZXh0KG9wdGlvbnMpIHtcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge31cblxuICAgICAgICB2YXIgY29udGV4dCA9IHtcbiAgICAgICAgICAgIHV0bTogZXh0cmFjdFVUTVBhcmFtcyhvcHRpb25zLnVybCksXG4gICAgICAgICAgICByZWZlcnJlcjogZGV0ZWN0UmVmZXJyZXIoKSxcbiAgICAgICAgICAgIHVzZXJBZ2VudDogZ2V0VXNlckFnZW50SW5mbygpLFxuICAgICAgICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgICAgICAgICAgaGFzVVRNOiBmYWxzZSxcbiAgICAgICAgICAgIHByaW1hcnlJbnRlbnQ6ICd1bmtub3duJ1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRGV0ZXJtaW5lIGlmIHdlIGhhdmUgVVRNIGRhdGFcbiAgICAgICAgY29udGV4dC5oYXNVVE0gPSBPYmplY3Qua2V5cyhjb250ZXh0LnV0bSkubGVuZ3RoID4gMFxuXG4gICAgICAgIC8vIEluZmVyIHByaW1hcnkgaW50ZW50XG4gICAgICAgIGNvbnRleHQucHJpbWFyeUludGVudCA9IGluZmVySW50ZW50KGNvbnRleHQpXG5cbiAgICAgICAgcmV0dXJuIGNvbnRleHRcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJbmZlciB1c2VyIGludGVudCBmcm9tIGNvbnRleHRcbiAgICAgKiBQcmlvcml0eTogVVRNIGNhbXBhaWduID4gVVRNIHNvdXJjZSA+IFJlZmVycmVyIGNhdGVnb3J5XG4gICAgICogQHBhcmFtIHtPYmplY3R9IGNvbnRleHQgLSBGdWxsIGNvbnRleHQgb2JqZWN0XG4gICAgICogQHJldHVybnMge3N0cmluZ30gLSBJbmZlcnJlZCBpbnRlbnQga2V5XG4gICAgICovXG4gICAgZnVuY3Rpb24gaW5mZXJJbnRlbnQoY29udGV4dCkge1xuICAgICAgICAvLyBQcmlvcml0eSAxOiBVVE0gY2FtcGFpZ24gdGVsbHMgdXMgdGhlIHNwZWNpZmljIGludGVudFxuICAgICAgICBpZiAoY29udGV4dC51dG0udXRtX2NhbXBhaWduKSB7XG4gICAgICAgICAgICB2YXIgY2FtcGFpZ24gPSBjb250ZXh0LnV0bS51dG1fY2FtcGFpZ24udG9Mb3dlckNhc2UoKVxuXG4gICAgICAgICAgICBpZiAoL3NhbGV8ZGlzY291bnR8b2ZmZXJ8cHJvbW8vaS50ZXN0KGNhbXBhaWduKSkgcmV0dXJuICdwcmljZS1mb2N1c2VkJ1xuICAgICAgICAgICAgaWYgKC9nYW1pbmd8Z2FtZXxlc3BvcnQvaS50ZXN0KGNhbXBhaWduKSkgcmV0dXJuICdnYW1pbmcnXG4gICAgICAgICAgICBpZiAoL3dvcmt8b2ZmaWNlfHByb2Zlc3Npb25hbHxwcm9kdWN0aXZpdHkvaS50ZXN0KGNhbXBhaWduKSkgcmV0dXJuICdwcm9mZXNzaW9uYWwnXG4gICAgICAgICAgICBpZiAoL2NyZWF0aXZlfGRlc2lnbnxhcnR8c3R1ZGlvL2kudGVzdChjYW1wYWlnbikpIHJldHVybiAnY3JlYXRpdmUnXG4gICAgICAgICAgICBpZiAoL2JyYW5kfHN0b3J5fGFib3V0L2kudGVzdChjYW1wYWlnbikpIHJldHVybiAnYnJhbmQtc3RvcnknXG4gICAgICAgIH1cblxuICAgICAgICAvLyBQcmlvcml0eSAyOiBVVE0gc291cmNlIGNhbiBpbmRpY2F0ZSBpbnRlbnRcbiAgICAgICAgaWYgKGNvbnRleHQudXRtLnV0bV9zb3VyY2UpIHtcbiAgICAgICAgICAgIHZhciBzb3VyY2UgPSBjb250ZXh0LnV0bS51dG1fc291cmNlLnRvTG93ZXJDYXNlKClcblxuICAgICAgICAgICAgaWYgKC9nb29nbGV8YmluZ3x5YWhvby9pLnRlc3Qoc291cmNlKSkgcmV0dXJuICdzZWFyY2gtb3B0aW1pemVkJ1xuICAgICAgICAgICAgaWYgKC9mYWNlYm9va3xpbnN0YWdyYW18dGlrdG9rL2kudGVzdChzb3VyY2UpKSByZXR1cm4gJ3NvY2lhbC12aXN1YWwnXG4gICAgICAgICAgICBpZiAoL3R3aXR0ZXJ8eCQvaS50ZXN0KHNvdXJjZSkpIHJldHVybiAnc29jaWFsLWJyaWVmJ1xuICAgICAgICAgICAgaWYgKC9lbWFpbHxuZXdzbGV0dGVyL2kudGVzdChzb3VyY2UpKSByZXR1cm4gJ3JldHVybmluZy11c2VyJ1xuICAgICAgICAgICAgaWYgKC95b3V0dWJlL2kudGVzdChzb3VyY2UpKSByZXR1cm4gJ3ZpZGVvLWVuZ2FnZWQnXG4gICAgICAgIH1cblxuICAgICAgICAvLyBQcmlvcml0eSAzOiBSZWZlcnJlciBjYXRlZ29yeVxuICAgICAgICBpZiAoY29udGV4dC5yZWZlcnJlci5jYXRlZ29yeSA9PT0gJ3NlYXJjaCcpIHJldHVybiAnc2VhcmNoLW9wdGltaXplZCdcbiAgICAgICAgaWYgKGNvbnRleHQucmVmZXJyZXIuY2F0ZWdvcnkgPT09ICdzb2NpYWwnKSByZXR1cm4gJ3NvY2lhbC12aXN1YWwnXG4gICAgICAgIGlmIChjb250ZXh0LnJlZmVycmVyLmNhdGVnb3J5ID09PSAnZW1haWwnKSByZXR1cm4gJ3JldHVybmluZy11c2VyJ1xuXG4gICAgICAgIC8vIERlZmF1bHRcbiAgICAgICAgcmV0dXJuICdkZWZhdWx0J1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBjb250ZXh0IHdpdGggdGltZW91dCBmYWxsYmFja1xuICAgICAqIFJldHVybnMgZGVmYXVsdCBjb250ZXh0IGlmIG9wZXJhdGlvbiB0YWtlcyB0b28gbG9uZ1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0aW9uc10gLSBDb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMudGltZW91dF0gLSBUaW1lb3V0IGluIG1zIChkZWZhdWx0OiAxMDAwKVxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IC0gQ29udGV4dCBvYmplY3RcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBnZXRDb250ZXh0QXN5bmMob3B0aW9ucykge1xuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fVxuICAgICAgICB2YXIgdGltZW91dCA9IG9wdGlvbnMudGltZW91dCB8fCBVVE1fVElNRU9VVF9NU1xuXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbiAocmVzb2x2ZSkge1xuICAgICAgICAgICAgdmFyIHRpbWVyID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgLy8gVGltZW91dDogcmV0dXJuIGRlZmF1bHQgY29udGV4dFxuICAgICAgICAgICAgICAgIHJlc29sdmUoe1xuICAgICAgICAgICAgICAgICAgICB1dG06IHt9LFxuICAgICAgICAgICAgICAgICAgICByZWZlcnJlcjogeyBzb3VyY2U6ICdkaXJlY3QnLCBjYXRlZ29yeTogJ2RpcmVjdCcsIHVybDogJycgfSxcbiAgICAgICAgICAgICAgICAgICAgdXNlckFnZW50OiB7IHJhdzogJycsIGlzTW9iaWxlOiBmYWxzZSwgaXNUYWJsZXQ6IGZhbHNlLCBpc0Rlc2t0b3A6IHRydWUgfSxcbiAgICAgICAgICAgICAgICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgICAgICAgICAgICAgICAgICBoYXNVVE06IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBwcmltYXJ5SW50ZW50OiAnZGVmYXVsdCcsXG4gICAgICAgICAgICAgICAgICAgIHRpbWVkT3V0OiB0cnVlXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0sIHRpbWVvdXQpXG5cbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvbnRleHQgPSBnZXRDb250ZXh0KG9wdGlvbnMpXG4gICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKVxuICAgICAgICAgICAgICAgIGNvbnRleHQudGltZWRPdXQgPSBmYWxzZVxuICAgICAgICAgICAgICAgIHJlc29sdmUoY29udGV4dClcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBjbGVhclRpbWVvdXQodGltZXIpXG4gICAgICAgICAgICAgICAgcmVzb2x2ZSh7XG4gICAgICAgICAgICAgICAgICAgIHV0bToge30sXG4gICAgICAgICAgICAgICAgICAgIHJlZmVycmVyOiB7IHNvdXJjZTogJ2RpcmVjdCcsIGNhdGVnb3J5OiAnZGlyZWN0JywgdXJsOiAnJyB9LFxuICAgICAgICAgICAgICAgICAgICB1c2VyQWdlbnQ6IHsgcmF3OiAnJywgaXNNb2JpbGU6IGZhbHNlLCBpc1RhYmxldDogZmFsc2UsIGlzRGVza3RvcDogdHJ1ZSB9LFxuICAgICAgICAgICAgICAgICAgICB0aW1lc3RhbXA6IERhdGUubm93KCksXG4gICAgICAgICAgICAgICAgICAgIGhhc1VUTTogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIHByaW1hcnlJbnRlbnQ6ICdkZWZhdWx0JyxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGUubWVzc2FnZVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgfVxuXG4gICAgLy8gLS0tIFB1YmxpYyBBUEkgLS0tXG4gICAgLy8gUmVnaXN0ZXIgb24gdGhlIGdsb2JhbCByb290ICh3aW5kb3cgaW4gYnJvd3NlcilcbiAgICB2YXIgTHVhVVRNID0ge1xuICAgICAgICBleHRyYWN0VVRNUGFyYW1zOiBleHRyYWN0VVRNUGFyYW1zLFxuICAgICAgICBzYW5pdGl6ZVBhcmFtOiBzYW5pdGl6ZVBhcmFtLFxuICAgICAgICBkZXRlY3RSZWZlcnJlcjogZGV0ZWN0UmVmZXJyZXIsXG4gICAgICAgIGdldFVzZXJBZ2VudEluZm86IGdldFVzZXJBZ2VudEluZm8sXG4gICAgICAgIGdldENvbnRleHQ6IGdldENvbnRleHQsXG4gICAgICAgIGdldENvbnRleHRBc3luYzogZ2V0Q29udGV4dEFzeW5jLFxuICAgICAgICBpbmZlckludGVudDogaW5mZXJJbnRlbnQsXG4gICAgICAgIFVUTV9QQVJBTVM6IFVUTV9QQVJBTVMsXG4gICAgICAgIFVUTV9USU1FT1VUX01TOiBVVE1fVElNRU9VVF9NUyxcbiAgICAgICAgUkVGRVJSRVJfUEFUVEVSTlM6IFJFRkVSUkVSX1BBVFRFUk5TLFxuICAgICAgICBSRUZFUlJFUl9DQVRFR09SSUVTOiBSRUZFUlJFUl9DQVRFR09SSUVTXG4gICAgfVxuXG4gICAgLy8gRXhwb3NlIGdsb2JhbGx5XG4gICAgcm9vdC5MdWFVVE0gPSBMdWFVVE1cblxufSkodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgPyB3aW5kb3cgOiB0eXBlb2YgZ2xvYmFsICE9PSAndW5kZWZpbmVkJyA/IGdsb2JhbCA6IHRoaXMpXG4iXSwibWFwcGluZ3Mi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