hyperclayjs 1.0.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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +360 -0
  3. package/README.template.md +276 -0
  4. package/communication/behaviorCollector.js +230 -0
  5. package/communication/sendMessage.js +48 -0
  6. package/communication/uploadFile.js +348 -0
  7. package/core/adminContenteditable.js +36 -0
  8. package/core/adminInputs.js +58 -0
  9. package/core/adminOnClick.js +31 -0
  10. package/core/adminResources.js +33 -0
  11. package/core/adminSystem.js +15 -0
  12. package/core/editmode.js +8 -0
  13. package/core/editmodeSystem.js +18 -0
  14. package/core/enablePersistentFormInputValues.js +62 -0
  15. package/core/isAdminOfCurrentResource.js +13 -0
  16. package/core/optionVisibilityRuleGenerator.js +160 -0
  17. package/core/savePage.js +196 -0
  18. package/core/savePageCore.js +236 -0
  19. package/core/setPageTypeOnDocumentElement.js +23 -0
  20. package/custom-attributes/ajaxElements.js +94 -0
  21. package/custom-attributes/autosize.js +17 -0
  22. package/custom-attributes/domHelpers.js +175 -0
  23. package/custom-attributes/events.js +15 -0
  24. package/custom-attributes/inputHelpers.js +11 -0
  25. package/custom-attributes/onclickaway.js +27 -0
  26. package/custom-attributes/onclone.js +35 -0
  27. package/custom-attributes/onpagemutation.js +20 -0
  28. package/custom-attributes/onrender.js +30 -0
  29. package/custom-attributes/preventEnter.js +13 -0
  30. package/custom-attributes/sortable.js +76 -0
  31. package/dom-utilities/All.js +412 -0
  32. package/dom-utilities/getDataFromForm.js +60 -0
  33. package/dom-utilities/insertStyleTag.js +28 -0
  34. package/dom-utilities/onDomReady.js +7 -0
  35. package/dom-utilities/onLoad.js +7 -0
  36. package/hyperclay.js +465 -0
  37. package/module-dependency-graph.json +612 -0
  38. package/package.json +95 -0
  39. package/string-utilities/copy-to-clipboard.js +35 -0
  40. package/string-utilities/emmet-html.js +54 -0
  41. package/string-utilities/query.js +1 -0
  42. package/string-utilities/slugify.js +21 -0
  43. package/ui/info.js +39 -0
  44. package/ui/prompts.js +179 -0
  45. package/ui/theModal.js +677 -0
  46. package/ui/toast.js +273 -0
  47. package/utilities/cookie.js +45 -0
  48. package/utilities/debounce.js +12 -0
  49. package/utilities/mutation.js +403 -0
  50. package/utilities/nearest.js +97 -0
  51. package/utilities/pipe.js +1 -0
  52. package/utilities/throttle.js +21 -0
  53. package/vendor/Sortable.js +3351 -0
  54. package/vendor/idiomorph.min.js +8 -0
  55. package/vendor/tailwind-base.css +1471 -0
  56. package/vendor/tailwind-play.js +169 -0
@@ -0,0 +1,35 @@
1
+ function copyToClipboard(text) {
2
+ // Create temporary textarea element
3
+ const textarea = document.createElement('textarea');
4
+ textarea.value = text;
5
+ textarea.style.position = 'fixed';
6
+ textarea.style.opacity = '0';
7
+
8
+ // Add to DOM, select, copy, and remove
9
+ document.body.appendChild(textarea);
10
+ textarea.select();
11
+ textarea.setSelectionRange(0, 99999); // For mobile devices
12
+
13
+ try {
14
+ const successful = document.execCommand('copy');
15
+ if (successful) {
16
+ console.log('Copied to clipboard');
17
+ } else {
18
+ console.log('Copy failed');
19
+ }
20
+ } catch (err) {
21
+ console.error('Unable to copy:', err);
22
+ }
23
+
24
+ document.body.removeChild(textarea);
25
+ }
26
+
27
+ // Export to window for global access
28
+ export function exportToWindow() {
29
+ if (!window.hyperclay) {
30
+ window.hyperclay = {};
31
+ }
32
+ window.hyperclay.copyToClipboard = copyToClipboard;
33
+ }
34
+
35
+ export default copyToClipboard;
@@ -0,0 +1,54 @@
1
+ export default function emmet(strings, ...values) {
2
+ // Extract the Emmet syntax from the first string
3
+ let emmetSyntax = strings[0];
4
+
5
+ // Reconstruct the content from the rest of the strings and values
6
+ let content = '';
7
+ for (let i = 1; i < strings.length; i++) {
8
+ content += values[i - 1];
9
+ content += strings[i];
10
+ }
11
+
12
+ // Parse the tag name
13
+ let tagMatch = emmetSyntax.match(/^([a-zA-Z][a-zA-Z0-9]*)/);
14
+ let tagName = tagMatch ? tagMatch[1] : 'div'; // Default to 'div' if no tag name is provided
15
+
16
+ // Parse class names
17
+ let classRegex = /\.([a-zA-Z0-9_-]+)/g;
18
+ let classNames = [];
19
+ let classMatch;
20
+ while ((classMatch = classRegex.exec(emmetSyntax)) !== null) {
21
+ classNames.push(classMatch[1]);
22
+ }
23
+
24
+ // Parse attributes
25
+ let attrRegex = /\[([^\]=]+)=([^\]]+)\]/g;
26
+ let attributes = {};
27
+ let attrMatch;
28
+ while ((attrMatch = attrRegex.exec(emmetSyntax)) !== null) {
29
+ attributes[attrMatch[1]] = attrMatch[2];
30
+ }
31
+
32
+ // Build the opening tag
33
+ let html = `<${tagName}`;
34
+
35
+ // Add classes if any
36
+ if (classNames.length > 0) {
37
+ html += ` class="${classNames.join(' ')}"`;
38
+ }
39
+
40
+ // Add attributes if any
41
+ for (let attr in attributes) {
42
+ html += ` ${attr}="${attributes[attr]}"`;
43
+ }
44
+
45
+ html += '>';
46
+
47
+ // Add the content
48
+ html += content;
49
+
50
+ // Close the tag
51
+ html += `</${tagName}>`;
52
+
53
+ return html;
54
+ }
@@ -0,0 +1 @@
1
+ export default Object.fromEntries(new URLSearchParams(window.location.search));
@@ -0,0 +1,21 @@
1
+ // e.g. "Hello there" → "hello-there"
2
+ function slugify (text) {
3
+ return text.toString().toLowerCase()
4
+ .normalize('NFD') // separate accents from letters
5
+ .replace(/[\u0300-\u036f]/g, '') // remove accents
6
+ .replace(/\s+/g, '-') // replace spaces with -
7
+ .replace(/[^\w\-]+/g, '') // remove all non-word chars
8
+ .replace(/\-\-+/g, '-') // replace multiple - with single -
9
+ .replace(/^-+/, '') // trim - from start of text
10
+ .replace(/-+$/, ''); // trim - from end of text
11
+ }
12
+
13
+ // Export to window for global access
14
+ export function exportToWindow() {
15
+ if (!window.hyperclay) {
16
+ window.hyperclay = {};
17
+ }
18
+ window.hyperclay.slugify = slugify;
19
+ }
20
+
21
+ export default slugify;
package/ui/info.js ADDED
@@ -0,0 +1,39 @@
1
+ import themodal from "./theModal.js";
2
+ import onDomReady from "../dom-utilities/onDomReady.js";
3
+
4
+ const CLOSE_BUTTON_SVG = `<svg class="group" viewBox="0 0 134 134" fill="none" xmlns="http://www.w3.org/2000/svg"><path class="fill-[#1D2032] group-hover:fill-[#212543]" d="M132 132.5 1 1.5h131v131Z" /><path fill-rule="evenodd" clip-rule="evenodd" d="M0 0h3v1.5h1.5V3H6v1.5h1.5V6H9v1.5h1.5V9H12v1.5h1.5V12H15v1.5h1.5V15H18v1.5h1.5V18H21v1.5h1.5V21H24v1.5h1.5V24H27v1.5h1.5V27H30v1.5h1.5V30H33v1.5h1.5V33H36v1.5h1.5V36H39v1.5h1.5V39H42v1.5h1.5V42H45v1.5h1.5V45H48v1.5h1.5V48H51v1.5h1.5V51H54v1.5h1.5V54H57v1.5h1.5V57H60v1.5h1.5V60H63v1.5h1.5V63H66v1.5h1.5V66H69v1.5h1.5V69H72v1.5h1.5V72H75v1.5h1.5V75H78v1.5h1.5V78H81v1.5h1.5V81H84v1.5h1.5V84H87v1.5h1.5V87H90v1.5h1.5V90H93v1.5h1.5V93H96v1.5h1.5V96H99v1.5h1.5V99h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v3h-3V132H129v-1.5h-1.5V129H126v-1.5h-1.5V126H123v-1.5h-1.5V123H120v-1.5h-1.5V120H117v-1.5h-1.5V117H114v-1.5h-1.5V114H111v-1.5h-1.5V111H108v-1.5h-1.5V108H105v-1.5h-1.5V105H102v-1.5h-1.5V102H99v-1.5h-1.5V99H96v-1.5h-1.5V96H93v-1.5h-1.5V93H90v-1.5h-1.5V90H87v-1.5h-1.5V87H84v-1.5h-1.5V84H81v-1.5h-1.5V81H78v-1.5h-1.5V78H75v-1.5h-1.5V75H72v-1.5h-1.5V72H69v-1.5h-1.5V69H66v-1.5h-1.5V66H63v-1.5h-1.5V63H60v-1.5h-1.5V60H57v-1.5h-1.5V57H54v-1.5h-1.5V54H51v-1.5h-1.5V51H48v-1.5h-1.5V48H45v-1.5h-1.5V45H42v-1.5h-1.5V42H39v-1.5h-1.5V39H36v-1.5h-1.5V36H33v-1.5h-1.5V33H30v-1.5h-1.5V30H27v-1.5h-1.5V27H24v-1.5h-1.5V24H21v-1.5h-1.5V21H18v-1.5h-1.5V18H15v-1.5h-1.5V15H12v-1.5h-1.5V12H9v-1.5H7.5V9H6V7.5H4.5V6H3V4.5H1.5V3H0V0ZM108.8 22h5.2v5.1h-2.6v2.6H109v2.6h-2.6v2.6h-2.6v2.5h-2.6v5.2h2.6V45h2.6v2.6h2.6v2.6h2.5v2.6h2.6V58h-5.1v-2.6h-2.6V53h-2.6v-2.6h-2.6v-2.6h-2.5v-2.6h-5.2v2.6H91v2.6h-2.6v2.6h-2.6v2.5h-2.6V58H78v-5.1h2.6v-2.6H83v-2.6h2.6v-2.6h2.6v-2.5h2.6v-5.2h-2.6V35h-2.6v-2.6h-2.6v-2.6h-2.5v-2.6H78V22h5.2v2.6h2.5V27h2.6v2.6h2.6v2.6h2.5v2.6h5.2v-2.6h2.5v-2.6h2.6v-2.6h2.6v-2.5h2.5V22Z" fill="#fff"/></svg>`;
5
+ const CONFIRM_BUTTON_SVG = `<div style="width: 28px;"><svg viewBox="0 0 60 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M34.5 0.75H43.5V5.25H49V9.75H54.5V14.25H60V18.75H54.5V23.25H49V27.75H43.5V32.25H34.5V27.75H40V23.25H45.5V18.75H0V14.25H45.5V9.75H40V5.25H34.5V0.75Z" fill="white"/></svg></div>`;
6
+
7
+ export function info (promptText, ...content) {
8
+ themodal.html = `<div class="max-w-[440px] space-y-5 mb-7">
9
+ <div class="text-[20px] sm:text-[22px] font-bold">${promptText}</div>
10
+ ${content.map(c => `<div class="text-[16px] sm:text-[18px] font-normal">${c}</div>`).join("")}
11
+ </div>`;
12
+ themodal.closeHtml = CLOSE_BUTTON_SVG;
13
+ themodal.yes = CONFIRM_BUTTON_SVG;
14
+
15
+ const promise = new Promise((resolve, reject) => {
16
+ themodal.onYes(() => {
17
+ resolve();
18
+ });
19
+
20
+ themodal.onNo = () => {
21
+ reject();
22
+ };
23
+ });
24
+
25
+ themodal.open();
26
+
27
+ return promise;
28
+ }
29
+
30
+ // Auto-initialize - cleanup any leftover modal elements
31
+ export function init() {
32
+ onDomReady(() => {
33
+ const micromodalParentElem = document.querySelector(".micromodal-parent");
34
+ if (micromodalParentElem) {
35
+ micromodalParentElem.remove();
36
+ document.body.style.overflow = "";
37
+ }
38
+ });
39
+ }
package/ui/prompts.js ADDED
@@ -0,0 +1,179 @@
1
+ import themodal from "./theModal.js";
2
+ import onDomReady from "../dom-utilities/onDomReady.js";
3
+ import toast from "./toast.js";
4
+ import copyToClipboard from "../string-utilities/copy-to-clipboard.js";
5
+
6
+ const CLOSE_BUTTON_SVG = `<svg class="group" viewBox="0 0 134 134" fill="none" xmlns="http://www.w3.org/2000/svg"><path class="fill-[#1D2032] group-hover:fill-[#212543]" d="M132 132.5 1 1.5h131v131Z" /><path fill-rule="evenodd" clip-rule="evenodd" d="M0 0h3v1.5h1.5V3H6v1.5h1.5V6H9v1.5h1.5V9H12v1.5h1.5V12H15v1.5h1.5V15H18v1.5h1.5V18H21v1.5h1.5V21H24v1.5h1.5V24H27v1.5h1.5V27H30v1.5h1.5V30H33v1.5h1.5V33H36v1.5h1.5V36H39v1.5h1.5V39H42v1.5h1.5V42H45v1.5h1.5V45H48v1.5h1.5V48H51v1.5h1.5V51H54v1.5h1.5V54H57v1.5h1.5V57H60v1.5h1.5V60H63v1.5h1.5V63H66v1.5h1.5V66H69v1.5h1.5V69H72v1.5h1.5V72H75v1.5h1.5V75H78v1.5h1.5V78H81v1.5h1.5V81H84v1.5h1.5V84H87v1.5h1.5V87H90v1.5h1.5V90H93v1.5h1.5V93H96v1.5h1.5V96H99v1.5h1.5V99h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v1.5h1.5v3h-3V132H129v-1.5h-1.5V129H126v-1.5h-1.5V126H123v-1.5h-1.5V123H120v-1.5h-1.5V120H117v-1.5h-1.5V117H114v-1.5h-1.5V114H111v-1.5h-1.5V111H108v-1.5h-1.5V108H105v-1.5h-1.5V105H102v-1.5h-1.5V102H99v-1.5h-1.5V99H96v-1.5h-1.5V96H93v-1.5h-1.5V93H90v-1.5h-1.5V90H87v-1.5h-1.5V87H84v-1.5h-1.5V84H81v-1.5h-1.5V81H78v-1.5h-1.5V78H75v-1.5h-1.5V75H72v-1.5h-1.5V72H69v-1.5h-1.5V69H66v-1.5h-1.5V66H63v-1.5h-1.5V63H60v-1.5h-1.5V60H57v-1.5h-1.5V57H54v-1.5h-1.5V54H51v-1.5h-1.5V51H48v-1.5h-1.5V48H45v-1.5h-1.5V45H42v-1.5h-1.5V42H39v-1.5h-1.5V39H36v-1.5h-1.5V36H33v-1.5h-1.5V33H30v-1.5h-1.5V30H27v-1.5h-1.5V27H24v-1.5h-1.5V24H21v-1.5h-1.5V21H18v-1.5h-1.5V18H15v-1.5h-1.5V15H12v-1.5h-1.5V12H9v-1.5H7.5V9H6V7.5H4.5V6H3V4.5H1.5V3H0V0ZM108.8 22h5.2v5.1h-2.6v2.6H109v2.6h-2.6v2.6h-2.6v2.5h-2.6v5.2h2.6V45h2.6v2.6h2.6v2.6h2.5v2.6h2.6V58h-5.1v-2.6h-2.6V53h-2.6v-2.6h-2.6v-2.6h-2.5v-2.6h-5.2v2.6H91v2.6h-2.6v2.6h-2.6v2.5h-2.6V58H78v-5.1h2.6v-2.6H83v-2.6h2.6v-2.6h2.6v-2.5h2.6v-5.2h-2.6V35h-2.6v-2.6h-2.6v-2.6h-2.5v-2.6H78V22h5.2v2.6h2.5V27h2.6v2.6h2.6v2.6h2.5v2.6h5.2v-2.6h2.5v-2.6h2.6v-2.6h2.6v-2.5h2.5V22Z" fill="#fff"/></svg>`;
7
+ const CONFIRM_BUTTON_SVG = `<div style="width: 28px;"><svg viewBox="0 0 60 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M34.5 0.75H43.5V5.25H49V9.75H54.5V14.25H60V18.75H54.5V23.25H49V27.75H43.5V32.25H34.5V27.75H40V23.25H45.5V18.75H0V14.25H45.5V9.75H40V5.25H34.5V0.75Z" fill="white"/></svg></div>`;
8
+
9
+ function createModal(promptText, yesCallback, extraContent = "", includeInput = false, defaultValue = "") {
10
+ const inputHtml = includeInput
11
+ ? `<div><input class="micromodal__input" type="text" value="${defaultValue}" required></div>`
12
+ : "";
13
+
14
+ themodal.html = `<div>
15
+ <div class="micromodal__heading">${promptText}</div>
16
+ ${inputHtml}
17
+ ${extraContent}
18
+ </div>`;
19
+ themodal.closeHtml = CLOSE_BUTTON_SVG;
20
+ themodal.yes = CONFIRM_BUTTON_SVG;
21
+
22
+ const promise = new Promise((resolve, reject) => {
23
+ themodal.onYes(() => {
24
+ try {
25
+ if (includeInput) {
26
+ const promptResult = document.querySelector(".micromodal__input").value;
27
+ if (promptResult) {
28
+ if (yesCallback) yesCallback(promptResult);
29
+ resolve(promptResult);
30
+ return true; // Allow modal to close
31
+ }
32
+ } else {
33
+ if (yesCallback) yesCallback();
34
+ resolve();
35
+ return true; // Allow modal to close
36
+ }
37
+ } catch (error) {
38
+ // Show error message as toast
39
+ toast(error.message || 'An error occurred', 'error');
40
+ // Keep modal open - don't reject or resolve
41
+ // User can try again
42
+ return false; // Prevent modal from closing
43
+ }
44
+ });
45
+
46
+ themodal.onNo = () => {
47
+ reject();
48
+ };
49
+ });
50
+
51
+ themodal.open();
52
+
53
+ return promise;
54
+ }
55
+
56
+ // Public API functions
57
+ export function ask(promptText, yesCallback, defaultValue = "", extraContent = "") {
58
+ return createModal(promptText, yesCallback, extraContent, true, defaultValue);
59
+ }
60
+
61
+ export function consent(promptText, yesCallback, extraContent = "") {
62
+ return createModal(promptText, yesCallback, extraContent, false);
63
+ }
64
+
65
+ export function tell(promptText, yesCallback, extraContent = "") {
66
+ return createModal(promptText, yesCallback, extraContent, false);
67
+ }
68
+
69
+ /**
70
+ * Display a modal with a code snippet and copy functionality
71
+ * Following the existing modal pattern from prompts.js
72
+ */
73
+ export function snippet(title, content, options = {}) {
74
+ const {
75
+ extraContent = 'Save this, it won\'t be shown again. Expires in 1 year.'
76
+ } = options;
77
+
78
+ // Create the modal content with copy button
79
+ const modalContent = `
80
+ <div class="bg-[#292E54] p-4 mb-[14px] max-w-[420px]">
81
+ <div class="overflow-x-auto">
82
+ <pre class="text-white font-mono text-sm whitespace-nowrap">${content}</pre>
83
+ </div>
84
+ </div>
85
+
86
+ <button type="button" class="custom-button group font-fixedsys text-center cursor-pointer border-[3px] border-t-[#474C65] border-r-[#131725] border-b-[#131725] border-l-[#474C65] bg-[#1D1F2F] hover:bg-[#232639] active:border-b-[#474C65] active:border-l-[#131725] active:border-t-[#131725] active:border-r-[#474C65] text-[23px] p-[2px_16px_4px] w-full mb-4 copy-snippet-btn">
87
+ <span class="whitespace-nowrap select-none inline-block group-active:translate-x-[1.5px] group-active:translate-y-[1.5px]">copy</span>
88
+ </button>
89
+
90
+ ${extraContent ? `
91
+ <div class="p-3 border-2 border-[#989742] bg-[#1E1E11] text-sm text-[#FBF7B7] max-w-[420px]">
92
+ ${extraContent}
93
+ </div>
94
+ ` : ''}
95
+ `;
96
+
97
+ // Use the existing modal system
98
+ themodal.html = `<div>
99
+ <div class="micromodal__heading">${title}</div>
100
+ ${modalContent}
101
+ </div>`;
102
+
103
+ themodal.closeHtml = CLOSE_BUTTON_SVG;
104
+ themodal.yes = CONFIRM_BUTTON_SVG;
105
+
106
+ const promise = new Promise((resolve) => {
107
+ // Local copy function
108
+ const handleCopy = function(event) {
109
+ if (event.target.closest('.copy-snippet-btn')) {
110
+ copyToClipboard(content);
111
+ toast('Copied to clipboard!', 'success');
112
+ }
113
+ };
114
+
115
+ // Add event listener to the modal container after it opens
116
+ setTimeout(() => {
117
+ const modalContainer = document.querySelector('.micromodal-parent');
118
+ if (modalContainer) {
119
+ modalContainer.addEventListener('click', handleCopy);
120
+ }
121
+ }, 0);
122
+
123
+ themodal.onYes(() => {
124
+ // Clean up the event listener
125
+ const modalContainer = document.querySelector('.micromodal-parent');
126
+ if (modalContainer) {
127
+ modalContainer.removeEventListener('click', handleCopy);
128
+ }
129
+ resolve();
130
+ return true;
131
+ });
132
+
133
+ themodal.onNo = () => {
134
+ // Clean up the event listener
135
+ const modalContainer = document.querySelector('.micromodal-parent');
136
+ if (modalContainer) {
137
+ modalContainer.removeEventListener('click', handleCopy);
138
+ }
139
+ resolve();
140
+ };
141
+ });
142
+
143
+ themodal.open();
144
+
145
+ return promise;
146
+ }
147
+
148
+ /**
149
+ * Show API key with standard warning
150
+ */
151
+ export function showApiKey(apiKey, username, expiresAt) {
152
+ return snippet('Sync API Key', apiKey, {
153
+ extraContent: `This key won't be shown again. Save it. Expires in 1 year.`
154
+ });
155
+ }
156
+
157
+ // Auto-initialize - cleanup any leftover modal elements
158
+ export function init() {
159
+ onDomReady(() => {
160
+ const micromodalParentElem = document.querySelector(".micromodal-parent");
161
+ if (micromodalParentElem) {
162
+ micromodalParentElem.remove();
163
+ document.body.style.overflow = "";
164
+ }
165
+ });
166
+ }
167
+
168
+ // Export to window for global access
169
+ export function exportToWindow() {
170
+ if (!window.hyperclay) {
171
+ window.hyperclay = {};
172
+ }
173
+
174
+ window.hyperclay.ask = ask;
175
+ window.hyperclay.consent = consent;
176
+ window.hyperclay.tell = tell;
177
+ window.hyperclay.snippet = snippet;
178
+ window.hyperclay.showApiKey = showApiKey;
179
+ }